如何在点击 pygame 后平滑移动图像?
How do I move an image smoothly after clicking in pygame?
我决定在 pygame 中制作我的游戏,这是我目前编写的代码:
from typing import Tuple
import pygame
from PIL import ImageGrab
# finding the height of the screen by taking a screenshot.
img = ImageGrab.grab()
(WIDTH, HEIGHT) = (img.size)
x = WIDTH / 2 - 470
y = HEIGHT / 2 - 400
fistx1 = x - 80
fistx2 = fistx1;
fisty1 = y + 40
fisty2 = y - 50
pygame.init()
clock = pygame.time.Clock()
RESOLUTION = (WIDTH, HEIGHT)
BACKGROUND_COLOR: Tuple[int, int, int] = (79, 205, 109)
MOVESPEED = 5
# window stuff
window = pygame.display.set_mode(RESOLUTION, flags=pygame.RESIZABLE, depth=32)
pygame.display.set_caption("The Connection")
window.fill(BACKGROUND_COLOR)
running = True
# all images for the game here
player_image = pygame.image.load("Connector.png")
player_fist1_image = pygame.image.load("Connector_hand.png")
player_fist2_image = player_fist1_image
while running:
pressed = pygame.key.get_pressed()
clicked = pygame.mouse.get_pressed();
class Player():
def __init__(self, hp, image, fist1image, fist2image):
global fisty1, fistx1, fisty2
self.hp = hp
self.image = image
self.fist1image = fist1image
self.fist2image = fist2image
window.blit(self.image, (x, y))
window.blit(self.fist1image, (fistx1, fisty1))
window.blit(self.fist2image, (fistx2, fisty2))
def move(self, movespeed):
global x, y, fistx1, fisty1, fisty2
if pressed[pygame.K_a]:
x -= movespeed
fistx1 -= movespeed
elif pressed[pygame.K_d]:
x += movespeed
fistx1 += movespeed
elif pressed[pygame.K_w]:
y -= movespeed
fisty1 -= movespeed
fisty2 -= movespeed
elif pressed[pygame.K_s]:
y += movespeed
fisty1 += movespeed
fisty2 += movespeed
def deal_damage(self, damage):
global x, y, fistx1, fisty1
fistx1 -= 25
window.fill(BACKGROUND_COLOR);
window.blit(self.fist1image, (fistx1, fisty1));
pygame.display.flip();
# this is the function we use to actually call it. This is more helpful and less confusing for an idiot like me
def actual_deal():
main_player.deal_damage(25);
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
try:
pygame.quit()
except pygame.error:
pass
if event.type == pygame.MOUSEBUTTONDOWN:
if event.button == 1:
actual_deal();
window.fill(BACKGROUND_COLOR)
main_player = Player(100, player_image, fist1image=player_fist1_image, fist2image=player_fist2_image)
main_player.move(movespeed=MOVESPEED)
pygame.display.flip()
clock.tick(60);
就上下文而言,拳头必须向前,然后向后。但是,拳头的动作并不流畅,这有两个问题:
看起来不太好。我想把它展示给其他人,所以我希望它看起来不错。
当我收回拳头的时候,看起来他们本来就不是向前的。我必须在两者之间添加 time.sleep
,但我不愿意这样做。
这是我打孔时得到的输出:
放置在扰流板中,因此不会造成干扰
如您所见,它以块状方式移动。如果你想看到我想要的输出,然后用 WASD 键移动角色,看看角色移动的流畅程度。我想要同样的拳头。
如果重要,我正在使用 pycharm 对此进行编码,并且我是 运行 从命令提示符。我也有 Windows 10.
最后,我尝试通过这样做来改变帧率:
以下是我已经看过的问题:
clock.tick(360);
但是没有用。
我看过这些问题:
smooth movement in pygame
https://gamedev.stackexchange.com/questions/48227/smooth-movement-pygame
我能认出其中的几个。首先,函数和 class 定义应该在主循环之外,因为在循环中一遍又一遍地定义相同的东西没有任何意义。其次,您调用 pygame.display.flip
两次,这是不需要的。 flip 只能调用一次,否则会导致闪烁。第三,您在 __init__
方法中绘制并每帧创建一个新实例。通常,一个实例只创建一次,并且该实例有一些方法可以对该实例执行某些操作。因此,不是在 __init__
中绘制,而是创建一个名为 draw.
的新方法
现在回答你的问题,它会成块移动,因为:
- 您一次移动它 25 帧,因此它一次跳过 25 个像素并在新位置再次绘制。
- 您正在使用
pygame.MOUSEBUTTONDOWN
。此函数每次点击仅 returns 一次为真。所以如果你按住你的鼠标按钮,它不会工作,因为它在第一帧 returns True
和之后 None
。要持续更新鼠标状态,需要使用pygame.mouse.get_pressed()
.
实现了我上面提到的所有内容的新代码(注意:我将图像更改为表面以使其工作,因此您可能想再次将其更改为图像):
from typing import Tuple
import pygame
from PIL import ImageGrab
# finding the height of the screen by taking a screenshot.
img = ImageGrab.grab()
(WIDTH, HEIGHT) = (img.size)
x = WIDTH / 2 - 470
y = HEIGHT / 2 - 400
fistx1 = x - 80
fistx2 = fistx1;
fisty1 = y + 40
fisty2 = y - 50
pygame.init()
clock = pygame.time.Clock()
RESOLUTION = (WIDTH, HEIGHT)
BACKGROUND_COLOR: Tuple[int, int, int] = (79, 205, 109)
MOVESPEED = 5
# window stuff
window = pygame.display.set_mode(RESOLUTION, flags=pygame.RESIZABLE, depth=32)
pygame.display.set_caption("The Connection")
window.fill(BACKGROUND_COLOR)
running = True
# all images for the game here
player_image = pygame.Surface((50, 50)).convert()
player_fist1_image = pygame.Surface((10, 10)).convert()
player_fist2_image = player_fist1_image
class Player():
def __init__(self, hp, image, fist1image, fist2image):
global fisty1, fistx1, fisty2
self.hp = hp
self.image = image
self.fist1image = fist1image
self.fist2image = fist2image
def move(self, movespeed):
global x, y, fistx1, fisty1, fisty2
if pressed[pygame.K_a]:
x -= movespeed
fistx1 -= movespeed
elif pressed[pygame.K_d]:
x += movespeed
fistx1 += movespeed
elif pressed[pygame.K_w]:
y -= movespeed
fisty1 -= movespeed
fisty2 -= movespeed
elif pressed[pygame.K_s]:
y += movespeed
fisty1 += movespeed
fisty2 += movespeed
def draw(self):
window.blit(self.image, (x, y))
window.blit(self.fist1image, (fistx1, fisty1))
window.blit(self.fist2image, (fistx2, fisty2))
def deal_damage(self, damage):
global x, y, fistx1, fisty1
mousePressed = pygame.mouse.get_pressed()
if mousePressed[0]:
fistx1 -= 1
window.fill(BACKGROUND_COLOR);
window.blit(self.fist1image, (fistx1, fisty1));
#pygame.display.flip();
main_player = Player(100, player_image, fist1image=player_fist1_image, fist2image=player_fist2_image)
# this is the function we use to actually call it. This is more helpful and less confusing for an idiot like me
def actual_deal():
main_player.deal_damage(25);
while running:
pressed = pygame.key.get_pressed()
clicked = pygame.mouse.get_pressed();
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
try:
pygame.quit()
except pygame.error:
pass
window.fill(BACKGROUND_COLOR)
main_player.move(movespeed=MOVESPEED)
main_player.deal_damage(50)
main_player.draw()
pygame.display.flip()
clock.tick(60);
编辑:忘记提及这一点,但您在 deal_damage
方法中采用了 damage
参数但未使用它。
添加到@hippozhipos 的回答中。使用 class
的一大好处是您不需要使用 global
变量。您只需将它们设置为属性即可。
您还试图在游戏循环中退出。
如果 running
是 False
它将退出你的游戏循环并自行退出。
也没有必要在你的循环之外填充,因为它每帧都会被填充。
我提供了一个最小的工作示例来说明如何实现。
import pygame
from PIL import ImageGrab
class Player():
def __init__(self, img, x, y, window):
self.fist = img
self.pos = (x - 80, y + 40)
self.win = window
def move(self, movespeed, pressed):
# here we maintain the players position with self.pos
# this allows you to have multiple instances
# with different positions
x, y = self.pos
if pressed[pygame.K_a]:
x -= movespeed
elif pressed[pygame.K_d]:
x += movespeed
elif pressed[pygame.K_w]:
y -= movespeed
elif pressed[pygame.K_s]:
y += movespeed
self.pos = (x, y)
def display(self):
self.win.blit(self.fist, self.pos)
pygame.init()
screenshot = ImageGrab.grab()
WIDTH, HEIGHT = screenshot.size
RESOLUTION = (WIDTH, HEIGHT)
BACKGROUND_COLOR = (79, 205, 109)
MOVESPEED = 5
window = pygame.display.set_mode(RESOLUTION, flags=pygame.RESIZABLE, depth=32)
pygame.display.set_caption("The Connection")
clock = pygame.time.Clock()
# this is whatever your image is
img = pygame.image.load('fist.png')
x = int(WIDTH / 2 - 470)
y = int(HEIGHT / 2 - 400)
main_player = Player(img=img, x=x, y=y, window=window)
running = True
while running:
pressed = pygame.key.get_pressed()
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
main_player.move(movespeed=MOVESPEED, pressed=pressed)
window.fill(BACKGROUND_COLOR)
main_player.display()
pygame.display.flip()
clock.tick(60)
我决定在 pygame 中制作我的游戏,这是我目前编写的代码:
from typing import Tuple
import pygame
from PIL import ImageGrab
# finding the height of the screen by taking a screenshot.
img = ImageGrab.grab()
(WIDTH, HEIGHT) = (img.size)
x = WIDTH / 2 - 470
y = HEIGHT / 2 - 400
fistx1 = x - 80
fistx2 = fistx1;
fisty1 = y + 40
fisty2 = y - 50
pygame.init()
clock = pygame.time.Clock()
RESOLUTION = (WIDTH, HEIGHT)
BACKGROUND_COLOR: Tuple[int, int, int] = (79, 205, 109)
MOVESPEED = 5
# window stuff
window = pygame.display.set_mode(RESOLUTION, flags=pygame.RESIZABLE, depth=32)
pygame.display.set_caption("The Connection")
window.fill(BACKGROUND_COLOR)
running = True
# all images for the game here
player_image = pygame.image.load("Connector.png")
player_fist1_image = pygame.image.load("Connector_hand.png")
player_fist2_image = player_fist1_image
while running:
pressed = pygame.key.get_pressed()
clicked = pygame.mouse.get_pressed();
class Player():
def __init__(self, hp, image, fist1image, fist2image):
global fisty1, fistx1, fisty2
self.hp = hp
self.image = image
self.fist1image = fist1image
self.fist2image = fist2image
window.blit(self.image, (x, y))
window.blit(self.fist1image, (fistx1, fisty1))
window.blit(self.fist2image, (fistx2, fisty2))
def move(self, movespeed):
global x, y, fistx1, fisty1, fisty2
if pressed[pygame.K_a]:
x -= movespeed
fistx1 -= movespeed
elif pressed[pygame.K_d]:
x += movespeed
fistx1 += movespeed
elif pressed[pygame.K_w]:
y -= movespeed
fisty1 -= movespeed
fisty2 -= movespeed
elif pressed[pygame.K_s]:
y += movespeed
fisty1 += movespeed
fisty2 += movespeed
def deal_damage(self, damage):
global x, y, fistx1, fisty1
fistx1 -= 25
window.fill(BACKGROUND_COLOR);
window.blit(self.fist1image, (fistx1, fisty1));
pygame.display.flip();
# this is the function we use to actually call it. This is more helpful and less confusing for an idiot like me
def actual_deal():
main_player.deal_damage(25);
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
try:
pygame.quit()
except pygame.error:
pass
if event.type == pygame.MOUSEBUTTONDOWN:
if event.button == 1:
actual_deal();
window.fill(BACKGROUND_COLOR)
main_player = Player(100, player_image, fist1image=player_fist1_image, fist2image=player_fist2_image)
main_player.move(movespeed=MOVESPEED)
pygame.display.flip()
clock.tick(60);
就上下文而言,拳头必须向前,然后向后。但是,拳头的动作并不流畅,这有两个问题:
看起来不太好。我想把它展示给其他人,所以我希望它看起来不错。
当我收回拳头的时候,看起来他们本来就不是向前的。我必须在两者之间添加
time.sleep
,但我不愿意这样做。
这是我打孔时得到的输出: 放置在扰流板中,因此不会造成干扰
如您所见,它以块状方式移动。如果你想看到我想要的输出,然后用 WASD 键移动角色,看看角色移动的流畅程度。我想要同样的拳头。
如果重要,我正在使用 pycharm 对此进行编码,并且我是 运行 从命令提示符。我也有 Windows 10.
最后,我尝试通过这样做来改变帧率:
以下是我已经看过的问题:
clock.tick(360);
但是没有用。
我看过这些问题:
smooth movement in pygame
https://gamedev.stackexchange.com/questions/48227/smooth-movement-pygame
我能认出其中的几个。首先,函数和 class 定义应该在主循环之外,因为在循环中一遍又一遍地定义相同的东西没有任何意义。其次,您调用 pygame.display.flip
两次,这是不需要的。 flip 只能调用一次,否则会导致闪烁。第三,您在 __init__
方法中绘制并每帧创建一个新实例。通常,一个实例只创建一次,并且该实例有一些方法可以对该实例执行某些操作。因此,不是在 __init__
中绘制,而是创建一个名为 draw.
现在回答你的问题,它会成块移动,因为:
- 您一次移动它 25 帧,因此它一次跳过 25 个像素并在新位置再次绘制。
- 您正在使用
pygame.MOUSEBUTTONDOWN
。此函数每次点击仅 returns 一次为真。所以如果你按住你的鼠标按钮,它不会工作,因为它在第一帧 returnsTrue
和之后None
。要持续更新鼠标状态,需要使用pygame.mouse.get_pressed()
.
实现了我上面提到的所有内容的新代码(注意:我将图像更改为表面以使其工作,因此您可能想再次将其更改为图像):
from typing import Tuple
import pygame
from PIL import ImageGrab
# finding the height of the screen by taking a screenshot.
img = ImageGrab.grab()
(WIDTH, HEIGHT) = (img.size)
x = WIDTH / 2 - 470
y = HEIGHT / 2 - 400
fistx1 = x - 80
fistx2 = fistx1;
fisty1 = y + 40
fisty2 = y - 50
pygame.init()
clock = pygame.time.Clock()
RESOLUTION = (WIDTH, HEIGHT)
BACKGROUND_COLOR: Tuple[int, int, int] = (79, 205, 109)
MOVESPEED = 5
# window stuff
window = pygame.display.set_mode(RESOLUTION, flags=pygame.RESIZABLE, depth=32)
pygame.display.set_caption("The Connection")
window.fill(BACKGROUND_COLOR)
running = True
# all images for the game here
player_image = pygame.Surface((50, 50)).convert()
player_fist1_image = pygame.Surface((10, 10)).convert()
player_fist2_image = player_fist1_image
class Player():
def __init__(self, hp, image, fist1image, fist2image):
global fisty1, fistx1, fisty2
self.hp = hp
self.image = image
self.fist1image = fist1image
self.fist2image = fist2image
def move(self, movespeed):
global x, y, fistx1, fisty1, fisty2
if pressed[pygame.K_a]:
x -= movespeed
fistx1 -= movespeed
elif pressed[pygame.K_d]:
x += movespeed
fistx1 += movespeed
elif pressed[pygame.K_w]:
y -= movespeed
fisty1 -= movespeed
fisty2 -= movespeed
elif pressed[pygame.K_s]:
y += movespeed
fisty1 += movespeed
fisty2 += movespeed
def draw(self):
window.blit(self.image, (x, y))
window.blit(self.fist1image, (fistx1, fisty1))
window.blit(self.fist2image, (fistx2, fisty2))
def deal_damage(self, damage):
global x, y, fistx1, fisty1
mousePressed = pygame.mouse.get_pressed()
if mousePressed[0]:
fistx1 -= 1
window.fill(BACKGROUND_COLOR);
window.blit(self.fist1image, (fistx1, fisty1));
#pygame.display.flip();
main_player = Player(100, player_image, fist1image=player_fist1_image, fist2image=player_fist2_image)
# this is the function we use to actually call it. This is more helpful and less confusing for an idiot like me
def actual_deal():
main_player.deal_damage(25);
while running:
pressed = pygame.key.get_pressed()
clicked = pygame.mouse.get_pressed();
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
try:
pygame.quit()
except pygame.error:
pass
window.fill(BACKGROUND_COLOR)
main_player.move(movespeed=MOVESPEED)
main_player.deal_damage(50)
main_player.draw()
pygame.display.flip()
clock.tick(60);
编辑:忘记提及这一点,但您在 deal_damage
方法中采用了 damage
参数但未使用它。
添加到@hippozhipos 的回答中。使用 class
的一大好处是您不需要使用 global
变量。您只需将它们设置为属性即可。
您还试图在游戏循环中退出。
如果 running
是 False
它将退出你的游戏循环并自行退出。
也没有必要在你的循环之外填充,因为它每帧都会被填充。
我提供了一个最小的工作示例来说明如何实现。
import pygame
from PIL import ImageGrab
class Player():
def __init__(self, img, x, y, window):
self.fist = img
self.pos = (x - 80, y + 40)
self.win = window
def move(self, movespeed, pressed):
# here we maintain the players position with self.pos
# this allows you to have multiple instances
# with different positions
x, y = self.pos
if pressed[pygame.K_a]:
x -= movespeed
elif pressed[pygame.K_d]:
x += movespeed
elif pressed[pygame.K_w]:
y -= movespeed
elif pressed[pygame.K_s]:
y += movespeed
self.pos = (x, y)
def display(self):
self.win.blit(self.fist, self.pos)
pygame.init()
screenshot = ImageGrab.grab()
WIDTH, HEIGHT = screenshot.size
RESOLUTION = (WIDTH, HEIGHT)
BACKGROUND_COLOR = (79, 205, 109)
MOVESPEED = 5
window = pygame.display.set_mode(RESOLUTION, flags=pygame.RESIZABLE, depth=32)
pygame.display.set_caption("The Connection")
clock = pygame.time.Clock()
# this is whatever your image is
img = pygame.image.load('fist.png')
x = int(WIDTH / 2 - 470)
y = int(HEIGHT / 2 - 400)
main_player = Player(img=img, x=x, y=y, window=window)
running = True
while running:
pressed = pygame.key.get_pressed()
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
main_player.move(movespeed=MOVESPEED, pressed=pressed)
window.fill(BACKGROUND_COLOR)
main_player.display()
pygame.display.flip()
clock.tick(60)