[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()




아래는 결과화면입니다.


끝.

댓글

이 블로그의 인기 게시물

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

NPN, PNP 트랜지스터 차이점

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

커패시터에 저장된 에너지 계산

3선 결선식 센서의 타입 PNP, NPN

제너 다이오드에 저항을 연결하는 이유

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

3상 모터 전력에서 전류 계산하기 (How to Convert Three-Phase Power to Amps)

[공압밸브] 5포트 2웨이 & 4포트 2웨이, 단동 VS 복동 차이점

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