Запуск частиц от игрока с постоянной скоростью с помощью cos () и sin () в python pygame

#python #pygame #game-physics #physics-engine

#python #пигмеи #игра-физика #физический движок

Вопрос:

В python pygame я пытаюсь заставить моего игрока стрелять частицей в направлении мыши, начиная с центра игроков

 class Particle:
    def __init__(self, ..., dx, dy, x, y):
        self.dx = dx
        self.dy = dy
        self.x = x
        self.y = y
        self.Rect = self.img.get_rect()

    def draw(self):
        self.x  = self.dx
        self.y  = self.dy
        self.Rect.centerx = self.x
        self.Rect.centery = self.y
        screen.blit(self.img, (self.Rect.x, self.Rect.y))
 

тета — это угол между центром проигрывателя и мышью в градусах в диапазоне от 0 до 360,
0 — положительное направление x

 dx = math.cos(theta) 
dy = math.sin(theta)
Particle(..., dx, dy, starting_x, starting_y)
 

Однако частицы, похоже, запускаются в случайных направлениях?

Полный код:

 import pygame
import math

FPS = 60
WHITE = (255, 255, 255)
RED = (255, 0, 0)
BLUE = (0, 0, 255)

pygame.init()

screen = pygame.display.set_mode([300, 300])

clock = pygame.time.Clock()

class Particle:
    def __init__(self, dx, dy, x, y):
        self.dx = dx
        self.dy = dy
        self.x = x
        self.y = y
        self.Rect = pygame.Rect(100, 150, 5, 5)


    def draw(self, screen):
        self.x  = self.dx
        self.y  = self.dy
        self.Rect.centerx = self.x
        self.Rect.centery = self.y
        pygame.draw.rect(screen, BLUE, self.Rect)


particles = []

done = False
while not done:

    screen.fill(WHITE)
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            done = True


        if pygame.mouse.get_pressed()[0]:
            mousex = pygame.mouse.get_pos()[0]
            mousey = pygame.mouse.get_pos()[1]

            theta = math.degrees(math.atan(player_rect.x - mousey/  player_rect.y - mousex))
            dx = math.cos(theta) 
            dy = math.sin(theta)
            particles.append(Particle(dx, dy, player_rect.x, player_rect.y))

    for particle in particles:
        particle.draw(screen)



    player_rect = pygame.Rect(100, 150, 10, 10)
    pygame.draw.rect(screen, RED, player_rect)
    clock.tick(FPS)
    pygame.display.update()
pygame.quit()
 

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

1. math.cos и math.sin используйте радианы ; итак, у вас theta = math.degrees(... , похоже, проблема. Если вы исправите эту очевидную проблему, решит ли это проблему?

2. sin и cos принимают угол в радианах, а не в градусах.

3. Кроме того, имейте в виду, что ось y должна быть обращена вспять ( -dy ), потому что ось y обычно направлена вверх, но в системе координат PyGame ось y направлена вниз.

4. Также имейте в виду основные арифметические правила. Деление вычисляется перед вычитанием.

5. Также дважды проверьте, что вы не вычитаете y из значений x.

Ответ №1:

Нет необходимости вычислять угол. Просто вычислите нормализованное направление (единичный вектор):

 dx, dy = mousex - player_rect.centerx, mousey - player_rect.centery
len = math.hypot(dx, dy)
if len > 0:
    particles.append(Particle(dx/len, dy/len, player_rect.centerx, player_rect.centery))
 

Центр прямоугольника player_rect.centerx , player_rect.centery соответственно player_rect.center , а не player_rect.x , player_rect.y .


Полный пример:

 import pygame
import math

FPS = 60
WHITE = (255, 255, 255)
RED = (255, 0, 0)
BLUE = (0, 0, 255)

pygame.init()
screen = pygame.display.set_mode([300, 300])
clock = pygame.time.Clock()

class Particle:
    def __init__(self, dx, dy, x, y):
        self.dx = dx
        self.dy = dy
        self.x = x
        self.y = y
        self.Rect = pygame.Rect(100, 150, 5, 5)

    def draw(self, screen):
        self.x  = self.dx
        self.y  = self.dy
        self.Rect.centerx = self.x
        self.Rect.centery = self.y
        pygame.draw.rect(screen, BLUE, self.Rect)

particles = []

done = False
while not done:
    screen.fill(WHITE)
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            done = True

        if pygame.mouse.get_pressed()[0]:
            mousex = pygame.mouse.get_pos()[0]
            mousey = pygame.mouse.get_pos()[1]

            dx, dy = mousex - player_rect.centerx, mousey - player_rect.centery
            len = math.hypot(dx, dy)
            if len > 0:
                particles.append(Particle(dx/len, dy/len, *player_rect.center))

    for particle in particles:
        particle.draw(screen)

    player_rect = pygame.Rect(100, 150, 10, 10)
    pygame.draw.rect(screen, RED, player_rect)
    pygame.display.flip()
    clock.tick(FPS)

pygame.quit()