#python #pygame
#python #pygame
Вопрос:
Мы с моим другом только начинаем учиться программировать с pygame на repl.it и для нашего первого «настоящего» проекта мы хотим создать олдскульное приключение, похожее на point’n’click.
Однако у нас есть проблема с перемещением персонажа, если мы щелкнем где-нибудь на экране, персонаж просто «телепортируется» туда, но мы хотим, чтобы это выглядело как можно более плавно.
Итак, по сути, мы хотим избавиться от «телепортации» персонажа и вместо этого получить плавный покадровый переход от текущего положения персонажа к положению мыши.
Мы уже пытались замедлить циклы while, чтобы мы могли проецировать символ каждый раз, когда выполняется цикл while, но это просто приводит к сбою всего сайта, мы также пытались сделать это за пределами repl.it на случай, если это была проблема с сайтом, но и там это не сработало.
#PMC = Character
#mpos = the mouse position
#mstate= the state of the mouse buttons (0 if nothing is pressed, 1 if a mouse
#button is pressed)
#charspeed = the speed at which the character moves (=1px)
```
#---PMC movement when mouse click-----------------------
#---x,y = mpos x2,y2 = characterpos
if mstate == (1,0,0):
#print('x: ', x, ' y: ', y, ' x2: ', x2, ' y2: ', y2) #debugging_positions
while x2 != x:
if x2>x:
x2-=charspeed
screen.blit(pmc, (x2-46, y2-184))
if x2<x:
x2 =charspeed
screen.blit(pmc, (x2-46, y2-184))
while y2 != y:
if y2>y:
y2 -= charspeed
screen.blit(pmc, (x2-46, y2-184))
if y2<y:
y2 = charspeed
screen.blit(pmc, (x2-46, y2-184))
Комментарии:
1. Кроме того, вы можете проверить щелчок мыши, подписав первое значение в кортеже
if mstate[0]: do stuff
.2. Кроме того, вы можете выполнить
screen.blit(pmc, (x2-46, y2-184))
только один раз в основном цикле, за пределами операторовwhile
andif
, которые вы показываете в вопросе
Ответ №1:
У вас есть игровой цикл, так что используйте его. Просто переместите персонажа на определенную позицию в каждом кадре. Например, перемещать символ на кадр step
:
step = 1
if x2 step <= x:
x2 = step
elif x2 - step >= x:
x2 -= step
else:
x2 = x
if y2 step <= y:
y2 = step
elif y2 - step >= y:
y2 -= step
else:
y2 = y
Для более сложного решения вам нужно вычислить евклидово расстояние от точки до цели. Используйте pygame.math.Vector2
для вычислений.
Вычислите расстояние от между последователем и спрайтом и единичный вектор направления от ( follower_x
, follower_y
) до ( mainsprite_x
, mainsprite_y
). Единичный вектор может быть вычислен путем деления вектора направления на расстояние или путем нормализации ( normalize()
) вектора направления:
target_vector = Vector2(mainsprite_x, mainsprite_y)
follower_vector = Vector2(follower_x, follower_y)
distance = follower_vector.distance_to(target_vector)
direction_vector = target_vector - follower_vector
if distance > 0:
direction_vector /= distance
Теперь вы можете определить точное step_distance
и двигаться в направлении следования спрайта:
if distance > 0:
new_follower_vector = follower_vector direction_vector * step_distance.
Определите a maximum_distance
и a minimum_distance
. Минимальное расстояние шага равно:
min_step = max(0, distance - maximum_distance)
Максимальное расстояние шага равно
max_step = distance - minimum_distance
Соберите все это вместе:
minimum_distance = 0
maximum_distance = 10000
target_vector = Vector2(mainsprite_x, mainsprite_y)
follower_vector = Vector2(follower_x, follower_y)
new_follower_vector = Vector2(follower_x, follower_y)
distance = follower_vector.distance_to(target_vector)
if distance > minimum_distance:
direction_vector = (target_vector - follower_vector) / distance
min_step = max(0, distance - maximum_distance)
max_step = distance - minimum_distance
step_distance = min_step (max_step - min_step) * LERP_FACTOR
new_follower_vector = follower_vector direction_vector * step_distance
Минимальный пример: repl.it/@Rabbid76/PyGame-FollowMouseSmoothly
import pygame
LERP_FACTOR = 0.05
minimum_distance = 25
maximum_distance = 100
def FollowMe(pops, fpos):
target_vector = pygame.math.Vector2(*pops)
follower_vector = pygame.math.Vector2(*fpos)
new_follower_vector = pygame.math.Vector2(*fpos)
distance = follower_vector.distance_to(target_vector)
if distance > minimum_distance:
direction_vector = (target_vector - follower_vector) / distance
min_step = max(0, distance - maximum_distance)
max_step = distance - minimum_distance
step_distance = min_step (max_step - min_step) * LERP_FACTOR
new_follower_vector = follower_vector direction_vector * step_distance
return (new_follower_vector.x, new_follower_vector.y)
pygame.init()
window = pygame.display.set_mode((500, 500))
clock = pygame.time.Clock()
follower = (100, 100)
run = True
while run:
clock.tick(60)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
player = pygame.mouse.get_pos()
follower = FollowMe(player, follower)
window.fill(0)
pygame.draw.circle(window, (0, 0, 255), player, 10)
pygame.draw.circle(window, (255, 0, 0), (round(follower[0]), round(follower[1])), 10)
pygame.display.flip()
Комментарии:
1. вау, это действительно хорошее решение для этого, большое спасибо. Хотя это немного сложно для нас из-за наших текущих знаний о phython: P.
2. @esms10 Все, что вам нужно сделать, это скопировать функцию
FollowMe
и вызватьx, y = FollowMe((x, y), (x2, y2))
.
Ответ №2:
Я бы не рекомендовал использовать repl.it так как он имеет тенденцию работать очень медленно.
Также ваш код должен выглядеть примерно так:
while True:
screen.fill((0,0,0))
stuff happens
if x2>x:
x2-=charspeed
elif x2<x:
x2 =charspeed
elif y2>y:
y2 -= charspeed
elif y2<y:
y2 = charspeed
screen.blit(pmc, (x2-46, y2-184))
pygame.display.flip()
Вы не обновляли отображение, пока оно не переместилось полностью на (x, y)
Комментарии:
1. О, да, это немного смущает, что мы сами этого не заметили, но спасибо, чувак: P.
2. и мы используем repl.it потому что это единственный известный нам онлайн-компилятор, который довольно удобен для пользователя, потому что мы только начали кодировать, поэтому мы в принципе ничего не знаем: P.