[python] pygame 움직이는 오브젝트 - 중력 적용

이전 포스트에서 pygame에서 움직이는 오브젝트 생성을 다루었습니다. 이번엔 오브젝트에 중력 효과를 더해 보고자 합니다. 각 오브젝트가 가진 속도 벡터와 중력 벡터를 더하여 최종 벡터를 생성합니다. 두 벡터를 더하는 공식을 유도하는데 사용된 개념을 표현하는 그림입니다.


두개의 2차원 벡터를 더하여 하나의 벡터를 출력하는 기능은 소스코드 상에서 addVectors() 함수로 정의되어 있으니 참고 바랍니다.


중력과 더불어, 오브젝트들이 무한정 움직이지 않게 하기 위해 마찰과 탄성 개념을 추가하였으며, 소스코드 상에서 drag, elasticity 상수로 정의되어 있습니다.


아래는 소스코드입니다.


import pygame
import random
import math

# 윈도우 타이틀
pygame.display.set_caption('Gravity Test')

# 배경화면 색상
background_color = (255,255,255)

# 윈도우 사이즈
(width, height) = (400, 400)
screen = pygame.display.set_mode((width, height))

# 항력
drag = 0.999

# 탄성
elasticity = 0.75

# 중력
gravity = (math.pi, 0.002)

# FPS 설정
clock = pygame.time.Clock()

# 파티클 생성
number_of_particles = 10
my_particles = []

def addVectors(v1, v2):
    angle1, length1 = v1
    angle2, length2 = v2
    x  = math.sin(angle1) * length1 + math.sin(angle2) * length2
    y  = math.cos(angle1) * length1 + math.cos(angle2) * length2
    
    angle = 0.5 * math.pi - math.atan2(y, x)
    length  = math.hypot(x, y)

    return (angle, length)

class Particle():
    def __init__(self, position, size):
        self.x, self.y = position
        self.size = size
        self.colour = (0, 0, 255)
        self.thickness = 1
        self.speed = 0
        self.angle = 0

    def display(self):
        pygame.draw.circle(screen, self.colour, (int(self.x), int(self.y)), self.size, self.thickness)

    def move(self, df):
        # 중력 적용
        self.angle, self.speed = addVectors((self.angle, self.speed), gravity)

        # df : 초당 프레임 수 (FPS에 따른 위치 보정)
        self.x += math.sin(self.angle) * self.speed * df
        self.y -= math.cos(self.angle) * self.speed * df
        
        # 항력 적용
        self.speed *= drag

    def bounce(self):
        if self.x > width - self.size:
            self.x = 2*(width - self.size) - self.x
            self.angle = - self.angle
            self.speed *= elasticity

        elif self.x < self.size:
            self.x = 2*self.size - self.x
            self.angle = - self.angle
            self.speed *= elasticity

        if self.y > height - self.size:
            self.y = 2*(height - self.size) - self.y
            self.angle = math.pi - self.angle
            self.speed *= elasticity

        elif self.y < self.size:
            self.y = 2*self.size - self.y
            self.angle = math.pi - self.angle
            self.speed *= elasticity

for n in range(number_of_particles):
    size = random.randint(10, 20)
    x = random.randint(size, width-size)
    y = random.randint(size, height-size)

    particle = Particle((x, y), size)
    particle.speed = random.random()
    particle.angle = random.uniform(0, math.pi*2)

    my_particles.append(particle)
    
running = True
while running:
    df = clock.tick(60)

    for event in pygame.event.get():
        # 닫기 버튼 감지
        if event.type == pygame.QUIT:
            running = False
        
    screen.fill(background_color)

    for particle in my_particles:
        particle.move(df)
        particle.bounce()
        particle.display()

    pygame.display.flip()




아래는 결과화면입니다.


끝.

댓글

이 블로그의 인기 게시물

공압 속도 제어: 미터인 vs 미터아웃

[PLC] 센서 NPN, PNP 출력 타입별 결선방법 (OMRON E2E-X 시리즈 3선식 배선)

[PLC] PLC 아날로그 입출력 기본

전력(kW) 계산하기 (직류, 교류 단상, 교류 삼상)

사각형의 넓이 공식의 증명

NPN, PNP 트랜지스터 차이점

[주식] 한국거래소(KRX) 데이터 API 입문 가이드

[아두이노] 가변저항(Potential Divider)과 전압분배(Voltage Divider)

[PLC] 래더 다이어그램과 PLC

[PLC] MC/MCR 명령 이해