Анимационный глюк в Pygame - PullRequest
2 голосов
/ 06 июля 2019

Я использую pygame, чтобы создать симуляцию столкновения двух блоков , имеющих массовые отношения в степени 100, чтобы быть понятным, это означает, что отношение большего блока к меньшему блоку может быть 100**0, 100**1, 100**2 и так далее.Я добавил комментарии и строки документации, где это необходимо, чтобы сделать логику понятной.

import pygame

# from collisions import *
pygame.init()

s1, s2 = 100, 50  # block sides
x1, y1 = 1000, 250  # bigger block coords
x2, y2 = 500, y1 + s1 - s2  # smaller block coords

power = int(input('enter: '))  # mass ratio
v1 = (-0.5)  # initial velocity of block 1

m1, m2 = 100 ** (power - 1), 1  # mass of blocks
v2 = 0  # initial velocity of block 2

# temp_x1 = 0
red = (255, 0, 0)
blue = (0, 0, 255)


def message_to_print(msg, color):
    font = pygame.font.SysFont(None, 40)
    text = font.render(msg, True, color)
    win.blit(text, [10, 10])


def reverse_vel(vel):
    '''
    reversing velocity of block
    '''
    vel *= -1
    return vel


def exchange_vel(v1, m1, v2, m2):
    '''
    this function is calculating the new velocity of the block after collision,
    based on law of conservation of momentum and kinetic energy
    '''
    v1 = ((m1 - m2) / (m1 + m2)) * v1 + ((2 * m2) / (m1 + m2)) * v2

    return v1  # returning new velocity after collision


win = pygame.display.set_mode((1200, 500))
win.fill((255, 255, 255))
pygame.display.set_caption('simulation')

Collisions = 0  # counting number of collisions
run = True
while run:
    # click_sound = pygame.mixer.Sound("rss/click.wav")
    # pygame.time.delay(10)
    # sound_collide, sound_reverse = True, True

    message_to_print('collision ' + str(Collisions), (0, 0, 0))
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            run = False

    # biger block
    x1 += v1  # changing block coordinates according to velocity
    if x1 > s2:  # this prevents block 1 from moving out of window
        t = x1

    if not x2 + s2 < x1 or x1 + s1 < x2:
        '''
        changing velocity after collision,
        storing them in temp variable for each block,
        then assiging new velocity
        '''
        v2_temp = exchange_vel(v2, m2, v1, m1)
        v1_temp = exchange_vel(v1, m1, v2, m2)
        # if sound_collide:
        # click_sound.play()
        # sound = False

        v2, v1 = v2_temp, v1_temp  # assigning new velocities
        Collisions += 1

    # smaller Block
    x2 += v2
    if x2 <= 0:
        '''
        if block 1 touch left wall, its velocity reverses, 
        '''
        v2 = reverse_vel(v2)
        # if sound_reverse:
        # click_sound.play()
        # sound_reverse = False
        Collisions += 1
    pygame.draw.rect(win, blue, (x2, y2, s2, s2))
    pygame.draw.rect(win, red, (t, y1, s1, s1))

    pygame.display.update()
    win.fill((255, 255, 255))

pygame.quit()

Задача 1:

Для меньшего значения power моделирование работает нормально,Но для значений power>=3 анимация блока 2 (синий блок) становится странной (как показано на рисунке), и я не могу найти причину и устранить ее.enter image description here

Как видно на изображении, синий блок всегда является этой позицией с постоянным исчезновением и появлением.

ОБНОВЛЕНИЕ: Количество происходящих столкновений является неотъемлемой частьюэта программа.В любом случае количество столкновений не должно быть затронуто

Ответы [ 2 ]

2 голосов
/ 06 июля 2019

Если скорость (v1, v2) больше 1, то столкновение не происходит точно в новой позиции объекта (после того, как v1 соответственно v2) было добавлено в позицию , Столкновение происходит где-то на трассе от x1 до x1+v1 соответственно x2 до x2+v2.

Разделить вычисления на шаги, где каждый шаг меньше 1 (пиксель), и выполнить вычисления в цикле. Обратите внимание, что вычисления выполняются с использованием значений с плавающей запятой, а не целых значений:

steps = max(abs(int(v1))+1, int(abs(v2))+1)
for i in range(steps):

    # biger block
    step_v1 = v1 / steps
    x1 += step_v1
    # [...]

    # smaller Block
    step_v2 = v2 / steps
    x2 += step_v2
    # [...]

Ограничить позиции небольшого блока после столкновения:

if x1 <= x2+s2:
    x2 = x1-s2
if x2 <= 0:
    x2 = 0

Поскольку координаты блоков являются значениями с плавающей запятой, перед использованием в pygame.draw.rect():

необходимо составить round() до целых значений
pygame.draw.rect(win, blue, (round(x2), round(y2), s2, s2))
pygame.draw.rect(win, red, (round(x1), round(y1), s1, s1))

Основной цикл и пример с enter: 4

Collisions = 0  # counting number of collisions
run = True
while run:

    message_to_print('collision ' + str(Collisions), (0, 0, 0))
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            run = False

    steps = max(abs(int(v1))+1, int(abs(v2))+1)
    for i in range(steps):

        # biger block
        step_v1 = v1 / steps
        x1 += step_v1

        if x1 <= x2+s2:
            x2 = x1-s2
            v2_temp = exchange_vel(v2, m2, v1, m1)
            v1_temp = exchange_vel(v1, m1, v2, m2)
            v2, v1 = v2_temp, v1_temp
            Collisions += 1

        # smaller Block
        step_v2 = v2 / steps
        x2 += step_v2
        if x2 <= 0:
            x2 = 0
            v2 = reverse_vel(v2)
            Collisions += 1

    pygame.draw.rect(win, blue, (round(x2), round(y2), s2, s2))
    pygame.draw.rect(win, red, (round(x1), round(y1), s1, s1))

    pygame.display.update()
    win.fill((255, 255, 255))
1 голос
/ 06 июля 2019

Я понимаю, что ты делаешь.Этого можно добиться, просто добавив оператор else, когда вы не позволяете блоку 1 выйти из окна.

if x1 >= s2:
    t = x1
    t2 = x2
else:
    t2 = 0

и изменить

pygame.draw.rect(win, blue, (t2, y2, s2, s2)) # x2-> t2

Объяснение: Когда ваша координата block1 равнабольше s2, тогда они будут иметь нормальные движения, но когда это не так, просто зафиксируйте координату меньшего блока равной 0.

Рекомендация: Поскольку практически в течение этого времени будут происходить столкновения, чтобы показать этов симуляции вы можете сделать что-то вроде этого.

    if x1 >= s2 +2:   # this prevents block 1 from moving out of window
    t = x1
    t2 = x2
else:
    t2 = z%2
z+=1

Это создаст эффект мини-столкновения.Я использовал 2 произвольный выбор.Также инициализируйте z=0 перед основным циклом

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...