在python/pygame中,如何控制角色在迷宫中移动的速度?
在过去的几天里,我一直在为一个学校项目重新制作游戏《吃豆人》。到目前为止,我只遇到了一个问题,那就是如何用我创建的代码降低字符的速度。如果能帮我找到解决问题的办法,我将不胜感激 下面是重现我的问题的代码:在python/pygame中,如何控制角色在迷宫中移动的速度?,python,pygame,pacman,Python,Pygame,Pacman,在过去的几天里,我一直在为一个学校项目重新制作游戏《吃豆人》。到目前为止,我只遇到了一个问题,那就是如何用我创建的代码降低字符的速度。如果能帮我找到解决问题的办法,我将不胜感激 下面是重现我的问题的代码: import pygame, sys from pygame.locals import * import random import math pygame.init() FPS=30 fpsClock=pygame.time.Clock() screen=pygame.display.s
import pygame, sys
from pygame.locals import *
import random
import math
pygame.init()
FPS=30
fpsClock=pygame.time.Clock()
screen=pygame.display.set_mode((608,800),0,32)
FILL=(0,162,232)
BLACK=(0,0,0)
pmsprite0=pygame.image.load('pmsprite0.png').convert()
pmsprite0.set_colorkey(FILL)
brick=pygame.image.load('brick.png').convert()
brick.set_colorkey(FILL)
def createMaze():
row1=[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]
row2=[1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,1]
row3=[1,0,1,1,0,1,1,1,0,1,0,1,1,1,0,1,1,0,1]
row4=[1,0,1,1,0,1,1,1,0,1,0,1,1,1,0,1,1,0,1]
row5=[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1]
row6=[1,0,1,1,0,1,0,1,1,1,1,1,0,1,0,1,1,0,1]
row7=[1,0,0,0,0,1,0,1,1,1,1,1,0,1,0,0,0,0,1]
row8=[1,1,1,1,0,1,0,0,0,1,0,0,0,1,0,1,1,1,1]
row9=[1,1,1,1,0,1,1,1,0,1,0,1,1,1,0,1,1,1,1]
row10=[1,1,1,1,0,1,0,0,0,0,0,0,0,1,0,1,1,1,1]
row11=[1,1,1,1,0,1,0,1,0,0,0,1,0,1,0,1,1,1,1]
row12=[1,1,1,1,0,1,0,1,0,0,0,1,0,1,0,1,1,1,1]
row13=[0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0]
row14=[1,1,1,1,0,1,0,1,1,1,1,1,0,1,0,1,1,1,1]
row15=[1,1,1,1,0,1,0,0,0,0,0,0,0,1,0,1,1,1,1]
row16=[1,1,1,1,0,1,0,1,1,1,1,1,0,1,0,1,1,1,1]
row17=[1,1,1,1,0,1,0,1,1,1,1,1,0,1,0,1,1,1,1]
row18=[1,1,1,1,0,0,0,0,0,1,0,0,0,0,0,1,1,1,1]
row19=[1,0,0,0,0,1,1,1,0,1,0,1,1,1,0,0,0,0,1]
row20=[1,0,1,1,0,0,0,0,0,0,0,0,0,0,0,1,1,0,1]
row21=[1,0,1,1,0,1,0,1,1,1,1,1,0,1,0,1,1,0,1]
row22=[1,0,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,0,1]
row23=[1,0,1,1,1,1,1,1,0,1,0,1,1,1,1,1,1,0,1]
row24=[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1]
row25=[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]
maze = [row1,row2,row3,row4,row5,row6,row7,row8,row9,row10,row11,row12,row13,row14,row15,row16,row17,row18,row19,row20,row21,row22,row23,row24,row25]
return (maze)
def drawMaze(maze):
for j in range(19):
for i in range(25):
x=j*32
y=i*32
if maze[i][j]==1:
screen.blit(brick,(x,y))
def pacmanblit(x,y):
screen.blit(pmsprite0,(x,y))
def movePacman(maze,row,column,direction,):
if direction=='left' and maze[row][column-1]==0:
column=column-1
if direction=='right' and maze[row][column+1]==0:
column=column+1
if direction=='up' and maze[row-1][column]==0:
row=row-1
if direction=='down' and maze[row+1][column]==0:
row=row+1
return row,column
row=19
column=9
maze=createMaze()
direction='none'
while True:
screen.fill(BLACK)
drawMaze(maze)
pacmanblit(column*32,row*32)
row,column=movePacman(maze,row,column,direction)
pygame.display.update()
for event in pygame.event.get():
if event.type==QUIT:
pygame.quit()
sys.exit()
keys=pygame.key.get_pressed()
if keys[K_LEFT] and maze[row][column-1]==0:
direction='left'
if keys[K_RIGHT] and maze[row][column+1]==0:
direction='right'
if keys[K_UP] and maze[row-1][column]==0:
direction='up'
if keys[K_DOWN] and maze[row+1][column]==0:
direction='down'
fpsClock.tick(FPS)
谢谢。我看到两种解决方案可用于您当前的代码:
time = 0
while True:
dt = clock.tick(FPS) / 1000 # 'dt' will be the amount of seconds since last loop.
time += dt
screen.fill(BLACK)
...
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
# Don't have this code inside the event loop! You'll be checking the keys state
# for every event in the loop, which is just unnecessary. You only need to do it once.
if time > 1: # Allows pacman to move once every second.
time = 0 # Reset the timer.
keys = pygame.key.get_pressed()
if keys[K_LEFT] and maze[row][column-1] == 0:
direction = 'left'
elif keys[K_RIGHT] and maze[row][column+1] == 0: # Use 'elif'! Pacman can't move both left and right.
direction = 'right'
if keys[K_UP] and maze[row-1][column] == 0:
direction = 'up'
elif keys[K_DOWN] and maze[row+1][column] == 0:
direction = 'down'
...
稍后,您可能希望使游戏与时间相关,这意味着您使用dt
变量(每个循环所需的时间)计算移动速度、时间等,而不是按帧进行计算。我有一个最小的例子下面,但它将需要你改变你的游戏如何工作一点
导入并初始化 每个模块都需要导入,pygame也不例外。尽管我们需要调用函数
pygame.init()
,以便正确初始化pygame中所有导入的模块。如果我们忘记了这一点,一些模块将无法工作。该函数还返回所有成功初始化和失败初始化的元组(如果模块未能初始化,则不会引发错误)
创造必需品 我们还需要创建一个显示。Pygame已经创建了一个(隐藏的)显示,所以我们需要做的就是设置显示模式(在本例中,我们只设置分辨率)。创建一个时钟以确保程序以固定速度更新也是一个好主意(否则它将以不同的速度运行,这取决于计算机的速度) 为了便于阅读,我们将在后面的代码中创建两个颜色常量,它们表示红色、绿色和蓝色(RGB)的元组。值从0(无灯光)到255(全灯光) 在pygame中,我们通常使用曲面来表示对象的外观,使用矩形来表示对象的位置。表面就像一张空白的纸,里面有颜色或图像。如果您正在创建一个类,那么应该将属性命名为image和rect,因为许多函数都会查找和使用这些属性。这样的类可以通过继承
pygame.sprite.sprite
类而受益,您可以从中了解到原因
游戏循环 现在我们已经为我们的游戏循环做好了一切准备。这是一个将在整个游戏中运行的循环,我们在其中处理事件并更新对象的屏幕和位置 首先,我们将确保循环以给定的FPS执行。我们在节目开始时定义了FPS并创建了时钟。下面的代码将确保我们的程序有足够的睡眠时间使循环重复我们定义的FPS数量。在本例中,每秒60次
clock.tick(FPS)
然后我们将处理事件。事件基本上是用户操作,例如移动鼠标或按键。Pygame将在队列中注册所有这些事件,我们通过调用Pygame.event.get()
获得该队列。我们可以对其进行迭代,检查是否有我们想要处理的事件。事件有一个类型属性,我们可以对照pygame模块中的常量检查该属性,以确定它是什么类型的事件
for event in pygame.event.get():
if event.type == pygame.QUIT: # The user pressed the close button in the top corner of the window.
quit()
# Close the program. Other methods like 'raise SystemExit' or 'sys.exit()'.
# Calling 'pygame.quit()' won't close the program! It will just uninitialize the modules.
我们还可以检查if event.type==pygame.KEYDOWN
以查看用户是否按下了某个键。在这种情况下,事件有一个属性键,我们可以检查它代表哪个键
for event in pygame.event.get():
if event.type == pygame.QUIT:
quit()
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_w:
rect.move_ip(0, -2) # Changes the rect's position.
elif event.key == pygame.K_s:
rect.move_ip(0, 2)
elif event.key == pygame.K_a:
rect.move_ip(-2, 0)
elif event.key == pygame.K_d:
rect.move_ip(2, 0)
现在我们需要显示我们的图像。首先,我们可能希望从以前的渲染中清除屏幕。我们通过用黑色填充整个屏幕来实现这一点(删除代码以了解为什么要清除它)。然后我们需要将我们的图像快速显示到屏幕上。Blitting本质上意味着将图像复制到另一个表面(在我们的例子中是屏幕)。最后,我们翻转或更新屏幕
当我们进行布告时,实际上并没有向用户显示任何内容。把它想象成一边是计算机,另一边是用户。计算机在屏幕的一侧绘制(光点),朝用户翻转,然后重复
screen.fill(BLACK)
screen.blit(image, rect)
pygame.display.update() # Or 'pygame.display.flip()'.
现在我们有一个基本的游戏!很无聊,是的,但基本要素在那里!结合您当前的Python知识,您应该能够创建一些很棒的东西
完整代码
略为改进的游戏机制 请注意,程序会检查我们何时按键,而不会检查我们何时按下按键。为了解决这个问题,我们可以引入一个速度变量。我们可以创建一个玩家类,使其更有组织性。为了避免与帧相关的移动(如果我们将FPS更改为30,则对象将以一半的速度移动),我们通过将刻度之间的时间传递给可移动对象来引入与时间相关的移动
import pygame
successes, failures = pygame.init()
print("Initializing pygame: {0} successes and {1} failures.".format(successes, failures))
screen = pygame.display.set_mode((720, 480))
clock = pygame.time.Clock()
FPS = 60
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
class Player(pygame.sprite.Sprite):
def __init__(self):
super().__init__()
self.image = pygame.Surface((32, 32))
self.image.fill(WHITE)
self.rect = self.image.get_rect() # Get rect of some size as 'image'.
self.velocity = [0, 0]
def update(self):
self.rect.move_ip(*self.velocity)
player = Player()
running = True
while running:
dt = clock.tick(FPS) / 1000 # Returns milliseconds between each call to 'tick'. The convert time to seconds.
screen.fill(BLACK) # Fill the screen with background color.
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_w:
player.velocity[1] = -200 * dt # 200 pixels per second
elif event.key == pygame.K_s:
player.velocity[1] = 200 * dt
elif event.key == pygame.K_a:
player.velocity[0] = -200 * dt
elif event.key == pygame.K_d:
player.velocity[0] = 200 * dt
elif event.type == pygame.KEYUP:
if event.key == pygame.K_w or event.key == pygame.K_s:
player.velocity[1] = 0
elif event.key == pygame.K_a or event.key == pygame.K_d:
player.velocity[0] = 0
player.update()
screen.blit(player.image, player.rect)
pygame.display.update() # Or pygame.display.flip()
print("Exited the game loop. Game will quit...")
quit() # Not actually necessary since the script will exit anyway.
这段代码还有很多地方需要改进。我建议你阅读pygame和Richard Jones的这篇文章,以获得更深入的了解
for event in pygame.event.get():
if event.type == pygame.QUIT: # The user pressed the close button in the top corner of the window.
quit()
# Close the program. Other methods like 'raise SystemExit' or 'sys.exit()'.
# Calling 'pygame.quit()' won't close the program! It will just uninitialize the modules.
for event in pygame.event.get():
if event.type == pygame.QUIT:
quit()
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_w:
rect.move_ip(0, -2) # Changes the rect's position.
elif event.key == pygame.K_s:
rect.move_ip(0, 2)
elif event.key == pygame.K_a:
rect.move_ip(-2, 0)
elif event.key == pygame.K_d:
rect.move_ip(2, 0)
screen.fill(BLACK)
screen.blit(image, rect)
pygame.display.update() # Or 'pygame.display.flip()'.
import pygame
successes, failures = pygame.init()
print("{0} successes and {1} failures".format(successes, failures))
screen = pygame.display.set_mode((720, 480))
clock = pygame.time.Clock()
FPS = 60 # Frames per second.
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
# RED = (255, 0, 0), GREEN = (0, 255, 0), BLUE = (0, 0, 255).
rect = pygame.Rect((0, 0), (32, 32))
image = pygame.Surface((32, 32))
image .fill(WHITE)
while True:
clock.tick(FPS)
for event in pygame.event.get():
if event.type == pygame.QUIT:
quit()
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_w:
rect.move_ip(0, -2)
elif event.key == pygame.K_s:
rect.move_ip(0, 2)
elif event.key == pygame.K_a:
rect.move_ip(-2, 0)
elif event.key == pygame.K_d:
rect.move_ip(2, 0)
screen.fill(BLACK)
screen.blit(image, rect)
pygame.display.update() # Or pygame.display.flip()
import pygame
successes, failures = pygame.init()
print("Initializing pygame: {0} successes and {1} failures.".format(successes, failures))
screen = pygame.display.set_mode((720, 480))
clock = pygame.time.Clock()
FPS = 60
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
class Player(pygame.sprite.Sprite):
def __init__(self):
super().__init__()
self.image = pygame.Surface((32, 32))
self.image.fill(WHITE)
self.rect = self.image.get_rect() # Get rect of some size as 'image'.
self.velocity = [0, 0]
def update(self):
self.rect.move_ip(*self.velocity)
player = Player()
running = True
while running:
dt = clock.tick(FPS) / 1000 # Returns milliseconds between each call to 'tick'. The convert time to seconds.
screen.fill(BLACK) # Fill the screen with background color.
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_w:
player.velocity[1] = -200 * dt # 200 pixels per second
elif event.key == pygame.K_s:
player.velocity[1] = 200 * dt
elif event.key == pygame.K_a:
player.velocity[0] = -200 * dt
elif event.key == pygame.K_d:
player.velocity[0] = 200 * dt
elif event.type == pygame.KEYUP:
if event.key == pygame.K_w or event.key == pygame.K_s:
player.velocity[1] = 0
elif event.key == pygame.K_a or event.key == pygame.K_d:
player.velocity[0] = 0
player.update()
screen.blit(player.image, player.rect)
pygame.display.update() # Or pygame.display.flip()
print("Exited the game loop. Game will quit...")
quit() # Not actually necessary since the script will exit anyway.