Как добавить трение в PyGame

#python #pygame

#python #pygame

Вопрос:

Я новичок в PyGame. Я хочу создать игру для уклонения, которую я сделал в Scratch 2. Представьте, что там летит космический корабль. У вас есть только управление по оси Y с помощью клавиш up и down. Когда спрайт движется, у него должно быть трение, подобное тому, что заставляет его скорость Y постепенно замедляться при нажатии клавиш up или down

Код:

 # import sys
from random import randint
import pygame
from pygame.locals import *
pygame.init()


clock = pygame.time.Clock()

fps = 60
up = False
down = False
player_location = [250 ,200]
friction = 0.9
force = 4
misy = randint(0, 400)
missile_loc = [590,misy]

player = pygame.image.load("spaceship.png")
missile = pygame.image.load("missile.png")

Window_size = (600,400)
pygame.display.set_caption("The Game")
screen = pygame.display.set_mode(Window_size, 0, 0)

player_rect = pygame.Rect(player_location[0], player_location[1], player.get_width(), player.get_height())
missile_rect = pygame.Rect(missile_loc[0], missile_loc[1], missile.get_width(), missile.get_height())

go = True
while go:

    screen.fill((146, 244, 255))
    pygame.draw.rect(screen, (0,0,0), player_rect)
    pygame.draw.rect(screen, (255,0,0), missile_rect)

    player_rect.x = player_location[0]
    player_rect.y = player_location[1]

    # player_location[1] *= friction

    if up == True:
        player_location[1] -= force
    if down == True:
        player_location[1]  = force

    for event in pygame.event.get():
        if event.type == QUIT:
            go = False
        if event.type == KEYDOWN:
            if event.key == K_UP:
                up = True
            if event.key == K_DOWN:
                down = True
        if event.type == KEYUP:
            if event.key == K_UP:
                up = False
            if event.key == K_DOWN:
                down = False

    pygame.display.update()
    clock.tick(fps)

pygame.quit()
 

Комментарии:

1. Что вы подразумеваете под трением? Вы имеете в виду сопротивление или какую-то воображаемую замедляющую силу? Нравится это ? Каким должен быть профиль скорости? Сначала корабль идет быстро, затем постепенно замедляется или что?

2. Поскольку трение как сила часто аппроксимируется с помощью F = F_n * mu , где F_n — нормальная сила, mu — коэффициент трения между двумя поверхностями скольжения (например, брюхом космического корабля и асфальтом, ой), но если он летит (особенно в космосе), трения как такового нет.

3. @Spacha На самом деле я закодировал эту строку, но я изменил ее для комментариев. Обратитесь к коду, который я предоставил. Я попробовал, и космическому кораблю показалось, что он просто прилипает к верхней части окна.

4. Я это видел. У вас было player_location[1] *= friction . Это делает ваше player_location[1] значение равным 0.0 за долю секунды, поэтому оно застревает в верхней части экрана. Попробуйте код, который я предоставил.

5. Спасибо всем за попытку мне помочь. На самом деле я сам нашел ответ после некоторых экспериментов.

Ответ №1:

Ну, вы можете продолжать умножать свою скорость на десятичное число (таким образом, имитируя трение) Кажется, что из вашего кода force зависит ваша скорость. Итак, создайте переменную с именем «замедление = 0,95», чем меньше десятичное число, тем быстрее замедляется объект.

Итак, в вашем игровом цикле (желательно в конце для вашего случая) вы можете умножить свою силу на замедление:

 force *= deceleration
 

Комментарии:

1. Я не думаю, что это будет работать так, как ожидалось (хотя я пока не совсем уверен, что требуется). Сила должна быть сброшена до исходного значения при KEYUP событии. Кроме того, он должен быть активен только тогда, когда применяется сила.

2. @AntonioKaram Я пробовал, но кажется, что космический корабль застревает в верхней части экрана. У меня есть cod3d, который я превратил в комментарий, используя #.

Ответ №2:

Как я уже сказал, я не совсем уверен, чего вы хотите, но вот тот, который дает вашему космическому кораблю постоянное замедление, пока он не остановится. Сила возвращается к нормальному состоянию при отпускании клавиши. Я исправлю это, если вы проясните свой вопрос.

 # import sys
from random import randint
import pygame
from pygame.locals import *
pygame.init()


clock = pygame.time.Clock()

fps = 60
up = False
down = False
player_location = [250 ,200]
friction = 0.9
force = 4
misy = randint(0, 400)
missile_loc = [590,misy]

player = pygame.image.load("spaceship.png")
missile = pygame.image.load("missile.png")

Window_size = (600,400)
pygame.display.set_caption("The Game")
screen = pygame.display.set_mode(Window_size, 0, 0)

player_rect = pygame.Rect(player_location[0], player_location[1], player.get_width(), player.get_height())
missile_rect = pygame.Rect(missile_loc[0], missile_loc[1], missile.get_width(), missile.get_height())

drag = 0.0
def vertical_velocity():
    global force, drag
    vel =  force / (drag   1)
    drag  = 0.05
    return vel

go = True
while go:

    screen.fill((146, 244, 255))
    pygame.draw.rect(screen, (0,0,0), player_rect)
    pygame.draw.rect(screen, (255,0,0), missile_rect)

    player_rect.x = int(player_location[0])
    player_rect.y = int(player_location[1])

    # player_location[1] *= friction

    if up == True:
        player_location[1] -= vertical_velocity()
    if down == True:
        player_location[1]  = vertical_velocity()

    for event in pygame.event.get():
        if event.type == QUIT:
            go = False
        if event.type == KEYDOWN:
            if event.key == K_UP:
                up = True
            if event.key == K_DOWN:
                down = True
        if event.type == KEYUP:
            if event.key == K_UP:
                up = False
                drag = 0.0
            if event.key == K_DOWN:
                down = False
                drag = 0.0

    pygame.display.update()
    clock.tick(fps)

pygame.quit()
 

Редактировать

Вот, например, линейные и нелинейные профили скорости:

 drag = 0.0
def vertical_velocity_nonlinear():
    global force, drag
    vel =  force / (drag   1)
    drag  = 0.05
    return vel

def vertical_velocity_linear():
    global force, drag
    vel = force   (1-1/4*drag)
    vel = vel if (vel >= 0) else 0.0
    drag  = 0.05
    return vel
 

И профили скорости, которые они дают (это, вероятно, не очень полезно, но здесь я иду). Первый — «нелинейный», а второй — «линейный».
Профили скорости

Ответ №3:

Я на самом деле решил это сам после некоторых экспериментов.

Код:

 # import sys
from random import randint
import pygame
from pygame.locals import *
pygame.init()


clock = pygame.time.Clock()

fps = 60
up = False
down = False
player_location = [250 ,200]
friction = 0.9
force = 0
misy = randint(0, 400)
missile_loc = [590,misy]

player = pygame.image.load("ship.png")
missile = pygame.image.load("missile.png")

Window_size = (600,400)
pygame.display.set_caption("The Game")
screen = pygame.display.set_mode(Window_size, 0, 0)

player_rect = pygame.Rect(player_location[0], player_location[1], player.get_width(), player.get_height())
missile_rect = pygame.Rect(missile_loc[0], missile_loc[1], missile.get_width(), missile.get_height())

go = True
while go:

    screen.fill((146, 244, 255))
    pygame.draw.rect(screen, (0,0,0), player_rect)
    pygame.draw.rect(screen, (255,0,0), missile_rect)

    screen.blit(player, player_location)
    screen.blit(missile, missile_loc)

    player_rect.x = player_location[0]
    player_rect.y = player_location[1]

    player_location[1]  = force

    force *= friction

    if up == True:
        force -= 1
    if down == True:
        force  = 1

    for event in pygame.event.get():
        if event.type == QUIT:
            go = False
        if event.type == KEYDOWN:
            if event.key == K_UP:
                up = True
            if event.key == K_DOWN:
                down = True
        if event.type == KEYUP:
            if event.key == K_UP:
                up = False
            if event.key == K_DOWN:
                down = False

    pygame.display.update()
    clock.tick(fps)

pygame.quit()
 

Ответ №4:

Для перемещения игрока я обычно использую x , y , moveX и moveY .

В этом коде игрок перемещается с помощью стрелок, с трением при движении влево-вправо и с прыжком. Просто используйте ту же операцию для движения вверх-вниз, и вы сможете видеть игрока сверху сцены.

Обратите внимание, что для проигрывателя используется класс.

 pressed = pygame.key.get_pressed() # get the pressed keys

if pressed[K_LEFT]:
    self.moveX -= 3000 * time_passed # time_passed is in seconds
if pressed[K_RIGHT]:
    self.moveX  = 3000 * time_passed
if pressed[K_UP]: # jump runs differently
    self.moveY  = -1200

self.moveX *= 0.95**(100 * time_passed) # slow down
                                        # 0.95 is friction (moveX *= 0.95 if 100 FPS)

if self.moveY < 1600:
    self.moveY  = 5000 * time_passed # go down

self.x  = self.moveX * time_passed # add the X movement
self.y  = self.moveY * time_passed # add the Y movement
 

Комментарии:

1. Я сам ответил на решение. Просто взгляните.

2. Я видел, но я хотел помочь вам, показав вам другой способ сделать это.