반응형

기본 정렬 알고리즘 세 가지(퀵, 머지, 힙)를 파이게임으로 시각화 해 보자.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
import os
import random
os.environ['PYGAME_HIDE_SUPPORT_PROMPT'= '1'
import pygame
from math import ceil, floor
 
pygame.init()
pygame.display.set_caption("Sorting Visualization")
screensize = (640580)
screen = pygame.display.set_mode(screensize)
clock = pygame.time.Clock()
framerate = 10
running = True
 
font = pygame.font.Font(None30)
text = font.render("Sorting Visualization\n\n" +
                   "*q: Quick Sorting [ O(nlogn) ]\n" +
                   "*m: Merge Sorting [ O(nlogn) ]\n" +
                   "*h: Heap Sorting [ O(nlogn) ]\n" +
                   "\n*g: Random Data Generation"True"gray")
text_pos = text.get_rect()
text_pos.center = (screen.get_width()/2, text_pos.height/2)
 
data_size = 64
data = list()
data_color = list()
 
def DataGenerator():
    global data
    global data_color
    
    data = [random.randint(10400for i in range(data_size)]
    data_color = [(random.randint(0255), random.randint(0255), random.randint(0255))
                  for i in range(data_size)]
    
DataGenerator()
 
def Visualize():
    screen.fill("black")
    screen.blit(text, text_pos)
    for i in range(data_size):
        pygame.draw.rect(screen, data_color[i], (i*10, screensize[1]-data[i], 10, data[i]))
    pygame.display.flip()
    clock.tick(framerate)
 
def Finalize():
    screen.fill("white")
    pygame.display.flip()
    clock.tick(framerate)
 
def EventHandler():
    for event in pygame.event.get():
        if event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE:
            return -1
        elif event.type == pygame.QUIT:
            exit()
 
def QuickSort(start, end):
    if start >= end:
        return
    pivot = start
    left = start + 1
    right = end
    
    while left <= right:
        if EventHandler() == -1:
            return
        
        while left <= end and data[left] <= data[pivot]:
            left += 1
        while right > start and data[right] >= data[pivot]:
            right -= 1            
        if left > right:
            data[right], data[pivot] = data[pivot], data[right]
            data_color[right], data_color[pivot] = data_color[pivot], data_color[right]
        else:
            data[left], data[right] = data[right], data[left]
            data_color[left], data_color[right] = data_color[right], data_color[left]
            
        Visualize()
            
    QuickSort(start, right-1)
    QuickSort(right+1, end)
 
def MergeSort_1(data_list, color_list):
    if len(data_list) < 2:        
        return data_list, color_list
    
    mid = len(data_list) // 2
    low_data_list, low_color_list = MergeSort_1(data_list[:mid], color_list[:mid])
    high_data_list, high_color_list = MergeSort_1(data_list[mid:], color_list[mid:])
    
    merged_data_list = list()
    merged_color_list = list()
    l = h = 0
    while l < len(low_data_list) and h < len(high_data_list):
        if low_data_list[l] < high_data_list[h]:
            merged_data_list.append(low_data_list[l])
            merged_color_list.append(low_color_list[l])
            l += 1
        else:
            merged_data_list.append(high_data_list[h])
            merged_color_list.append(high_color_list[h])
            h += 1
            
    merged_data_list += low_data_list[l:]
    merged_color_list += low_color_list[l:]
    
    merged_data_list += high_data_list[h:]
    merged_color_list += high_color_list[h:]
    
    return merged_data_list, merged_color_list
 
def MergeSort_2():
    def sort(low, high):
        if EventHandler() == -1:
            return
        
        if high - low < 2:
            return
        
        mid = (low + high) // 2
        sort(low, mid)
        sort(mid, high)
        merge(low, mid, high)
 
    def merge(low, mid, high):
        data_temp = list()
        color_temp = list()
        l, h = low, mid
        
        while l < mid and h < high:
            if data[l] < data[h]:
                data_temp.append(data[l])
                color_temp.append(data_color[l])
                l += 1
            else:
                data_temp.append(data[h])
                color_temp.append(data_color[h])
                h += 1
                
        while l < mid:
            data_temp.append(data[l])
            color_temp.append(data_color[l])
            l += 1
            
        while h < high:
            data_temp.append(data[h])
            color_temp.append(data_color[h])
            h += 1
            
        for i in range(low, high):
            data[i] = data_temp[i - low]
            data_color[i] = color_temp[i - low]
            
            Visualize()            
 
    sort(0, data_size)
 
def HeapSort():
    for i in range(len(data)):
        par = ceil(i/2- 1
        while par >= 0 and data[par] < data[i]:
            data[par], data[i] = data[i], data[par]
            data_color[par], data_color[i] = data_color[i], data_color[par]
            i = par
            par = floor((i-1)/2)
 
    for i in range(len(data)-10-1):
        data[0], data[i] = data[i], data[0]
        data_color[0], data_color[i] = data_color[i], data_color[0]
 
        cur = 0
        lch = 1
        rch = 2
        
        while True:
            if EventHandler() == -1:
                return
        
            if rch < i and data[lch] < data[rch]:
                lch = rch
                
            if lch < i and data[lch] > data[cur]:
                data[lch], data[cur] = data[cur], data[lch]
                data_color[lch], data_color[cur] = data_color[cur], data_color[lch]
                
                Visualize()
                
                cur = lch
                lch = cur * 2 + 1
                rch = cur * 2 + 2
            else:
                lch = i # break와 같은 효과
                
            if not lch < i:
                break
            
while running:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False
        elif event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE:
            running = False
        elif event.type == pygame.KEYDOWN and event.key == pygame.K_q:
            QuickSort(0, data_size - 1)
            Finalize()
        elif event.type == pygame.KEYDOWN and event.key == pygame.K_m:
            MergeSort_2()
            Finalize()
        elif event.type == pygame.KEYDOWN and event.key == pygame.K_n:
            data, data_color = MergeSort_1(data, data_color)
            Finalize()
        elif event.type == pygame.KEYDOWN and event.key == pygame.K_h:
            HeapSort()
            Finalize()
        elif event.type == pygame.KEYDOWN and event.key == pygame.K_g:
            DataGenerator()
            
   Visualize()
 

 

코드를 작성하고 실행한다.

 

 

※ 참고

2024.03.09 - [Python] - [Pygame] Sorting Algorithms in Python 파이썬 정렬 알고리즘 1

 

알고리즘_05_강의록.pdf
3.91MB
알고리즘_04_강의록.pdf
1.86MB

 

 

 

반응형
Posted by J-sean
:
반응형

기본 정렬 알고리즘 네 가지(선택, 버블, 삽입, 셸)를 파이게임으로 시각화 해 보자.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
import os
import random
os.environ['PYGAME_HIDE_SUPPORT_PROMPT'= '1'
import pygame
 
pygame.init()
pygame.display.set_caption("Sorting Visualization")
screensize = (640580)
screen = pygame.display.set_mode(screensize)
clock = pygame.time.Clock()
framerate = 10
running = True
 
font = pygame.font.Font(None30)
text = font.render("Sorting Visualization\n\n" +
                   "*s: Selection Sorting [ O(n^2) ]\n" +
                   "*b: Bubble Sorting [ O(n^2) ]\n" +
                   "*i: Insertion Sorting [ O(n^2) ]\n" +
                   "*h: Shell Sorting [ O(n^2) ]\n" +
                   "\n*g: Random Data Generation"True"gray")
text_pos = text.get_rect()
text_pos.center = (screen.get_width()/2, text_pos.height/2)
 
data_size = 64
data = list()
data_color = list()
 
def DataGenerator():
    global data
    global data_color
    
    data = [random.randint(10400for i in range(data_size)]
    data_color = [(random.randint(0255), random.randint(0255), random.randint(0255))
                  for i in range(data_size)]
    
DataGenerator()
 
def Visualize():
    screen.fill("black")
    screen.blit(text, text_pos)
    for i in range(data_size):
        pygame.draw.rect(screen, data_color[i], (i*10, screensize[1]-data[i], 10, data[i]))
    pygame.display.flip()
    clock.tick(framerate)
 
def Finalize():
    screen.fill("white")
    pygame.display.flip()
    clock.tick(framerate)
 
def EventHandler():
    # 이벤트 처리하는 코드가 없으면 정렬시 프로그램이 freeze된다.
    for event in pygame.event.get():            
        if event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE:
            return -1 # 정렬 중지.
        elif event.type == pygame.QUIT:
            exit() # 프로그램 종료.
 
def SelectSort():
    for i in range(data_size-1):        
        if EventHandler() == -1:
            return
        
        min = i
        for j in range(i+1, data_size, 1):
            if data[min] > data[j]:
                min = j
        data[i], data[min] = data[min], data[i]        
        data_color[i], data_color[min] = data_color[min], data_color[i]
 
        Visualize()
    Finalize()
 
def BubbleSort(): 
    for i in range(data_size-1):
        if EventHandler() == -1:
            return
        
        sorted = True
        for j in range(data_size-1-i):
            if data[j] > data[j+1]:
                data[j], data[j+1= data[j+1], data[j]
                data_color[j], data_color[j+1= data_color[j+1], data_color[j]
                sorted = False
        if sorted == True:
            break
        
        Visualize()
    Finalize()
 
def InsertSort(): 
    for i in range(1, data_size, 1):
        if EventHandler() == -1:
            return
        
        val = data[i]
        colval = data_color[i]
        for j in range(i, 0-1):
            if data[j-1> val:
                data[j] = data[j-1]
                data_color[j] = data_color[j-1]
                j = j-1
            else:
                break
        data[j] = val
        data_color[j] = colval
        
        Visualize()
    Finalize()
    
def ShellSort():
    # 점화식 리스트 만들기
    recurrence = [1]
    while(True):
        next = recurrence[-1]*3+1
        if next < data_size:
            recurrence.append(next)
        else:
            recurrence.reverse()
            break
        
    for D in recurrence:
        for i in range(D, data_size, 1):
            if EventHandler() == -1:
                return
 
            val = data[i]
            colval = data_color[i]
            j = i
            while True:
                if j>=and data[j-D]>val:
                    data[j] = data[j-D]
                    data_color[j] = data_color[j-D]
                    j = j-D
                else:
                    break
            data[j] = val
            data_color[j] = colval
 
            Visualize()
    Finalize()
                
while running:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False
        elif event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE:
            running = False
        elif event.type == pygame.KEYDOWN and event.key == pygame.K_s:
            SelectSort()
        elif event.type == pygame.KEYDOWN and event.key == pygame.K_b:
            BubbleSort()
        elif event.type == pygame.KEYDOWN and event.key == pygame.K_i:
            InsertSort()
        elif event.type == pygame.KEYDOWN and event.key == pygame.K_h:
            ShellSort()
        elif event.type == pygame.KEYDOWN and event.key == pygame.K_g:
            DataGenerator()
            
   Visualize()
 

 

코드를 작성하고 실행한다.

 

 

※ 참고

2024.03.22 - [Python] - [Pygame] Sorting Algorithms in Python 파이썬 정렬 알고리즘 2

 

알고리즘_03_강의록.pdf
1.02MB
알고리즘_04_강의록.pdf
1.86MB

 

 

반응형
Posted by J-sean
:
반응형

중력이 적용된 캐릭터를 만들어 보자.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
import pygame
 
pygame.init()
pygame.display.set_caption("Super fun game development")
screen = pygame.display.set_mode((640480), vsync=1)
clock = pygame.time.Clock()
FPS = 60
running = True
 
# 플레이어 클래스 with Gravity
class Player(pygame.sprite.Sprite):
    def __init__(self, position):
        pygame.sprite.Sprite.__init__(self)
 
        self.direction = -1
        self.speed = 4
        self.image = pygame.image.load("player.png").convert()
        self.image.set_colorkey(self.image.get_at((00)))
        self.size = (self.image.get_width()*1.5self.image.get_height()*1.5)
        self.image = pygame.transform.scale(self.image, self.size)
        self.rect = self.image.get_rect(center=position)
        self.isGround = False
        self.jumpForce = 0.0
        self.gravity = 5.0
 
    def flip_image(self):
        self.image = pygame.transform.flip(self.image, TrueFalse)
 
    def update(self):
        global running
 
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                running = False
            elif event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE:
                running = False
 
        keys = pygame.key.get_pressed()
        if keys[pygame.K_LEFT]:
            if self.direction > 0:
                self.flip_image()
                self.direction = -1
            self.rect.move_ip(-self.speed, 0)
        if keys[pygame.K_RIGHT]:
            if self.direction < 0:
                self.flip_image()
                self.direction = 1
            self.rect.move_ip(self.speed, 0)
        if keys[pygame.K_UP]:
            if self.isGround:
                self.jumpForce = -17
 
        if not self.isGround:
            self.rect.centery += self.gravity + self.jumpForce
            self.gravity += 0.3
        else:
            self.rect.centery += self.jumpForce
            self.gravity = 5.0
 
        if self.jumpForce < 0:
            self.jumpForce += 0.10
        elif self.jumpForce >= 0:
            self.jumpForce = 0.0
 
# 버블 클래스
class Bubble(pygame.sprite.Sprite):
    def __init__(self, position):
        pygame.sprite.Sprite.__init__(self)
 
        self.image = pygame.image.load("bubble.png").convert()
        self.image.set_colorkey(self.image.get_at((00)))
        self.size = (self.image.get_width()*6self.image.get_height()*6)
        self.image = pygame.transform.scale(self.image, self.size)
        self.rect = self.image.get_rect(center=position)
        self.collided = False
 
    def update(self):
        if self.collided == True:
            self.rect.top -= 1
 
# 그라운드 클래스
class Ground(pygame.sprite.Sprite):
    def __init__(self, position):
        pygame.sprite.Sprite.__init__(self)
 
        self.image = pygame.image.load("ground.png").convert()
        self.rect = self.image.get_rect(bottomleft=position)
         
    def update(self):
        pass
 
def main():
    player = Player((screen.get_width()/2, screen.get_height()/2))
    player_sprite = pygame.sprite.Group(player)
    # 플레이어 스프라이트 그룹
 
    bubbles = [
        Bubble((40, screen.get_height()/2)),
        Bubble((160, screen.get_height()/2)),
        Bubble((480, screen.get_height()/2)),
        Bubble((600, screen.get_height()/2))]
    bubble_sprites = pygame.sprite.Group(bubbles)
    # 버블 스프라이트 그룹
 
    grounds = [
        Ground((0480)),
        Ground((440480))]
    ground_sprites = pygame.sprite.Group(grounds)
 
    all_sprites = pygame.sprite.Group()
    all_sprites.add(player_sprite)
    all_sprites.add(bubble_sprites)
    all_sprites.add(ground_sprites)
 
    while running:
 
        #player_sprite.update()
        #bubble_sprites.update()
        all_sprites.update()
 
        collision = pygame.sprite.spritecollide(player, bubble_sprites, False)
        for bubble in collision:
            bubble.collided = True
        # 플레이어와 버블의 충돌을 감지하고 충돌한 버블의 collided 값을 True로 바꾼다.
 
        collision = pygame.sprite.spritecollide(player, ground_sprites, False)
        if len(collision) != 0:
            player.isGround = True
            player.jumpForce = 0.0
            player.rect.bottom = collision[0].rect.top
        else:
            player.isGround = False
 
        screen.fill("black")
        #player_sprite.draw(screen)
        #bubble_sprites.draw(screen)
        #ground_sprites.draw(screen)
        all_sprites.draw(screen)
 
        pygame.display.flip()
        clock.tick(FPS)
 
    pygame.quit()
 
if __name__ == '__main__':
  main()
 

 

코드를 입력하고 실행한다.

 

캐릭터에 중력이 적용되어 움직인다.

 

반응형
Posted by J-sean
:
반응형

파이게임에 간단한 카메라를 만들어 보자.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
import pygame
 
pygame.init()
pygame.display.set_caption("Pygame Simple Camera")
screen = pygame.display.set_mode((640480), flags=pygame.RESIZABLE, vsync=1)
clock = pygame.time.Clock()
 
class Camera():
    def __init__(self):
        self.offset = pygame.math.Vector2(00)
        self.speed = 4
        
camera = Camera()
 
def LoadImage(path, scale=None, colorkey=None):
    image = pygame.image.load(path).convert()
 
    if scale is not None:
        image = pygame.transform.scale(image, (image.get_width()*scale, image.get_height()*scale))
 
    if colorkey is not None:
        if colorkey == -1:
            colorkey = image.get_at((00))
        image.set_colorkey(colorkey)
 
    return image
 
class Sprite(pygame.sprite.Sprite):
    def __init__(self, spriteName, position, frames):
        pygame.sprite.Sprite.__init__(self)
 
        self.elapsedTime = 0
        self.limitTime = 1000/frames
        # 1초에 한 사이클. 스프라이트가 8프레임이라면 frames에 8을 대입한다.
        
        self.direction = 1
        self.speed = 4
        self.index = 0
        self.images = [ LoadImage(spriteName, 3-1) ]
        self.image = self.images[self.index]
        self.rect = self.image.get_rect(center=position)
 
    def flip_image(self):
        self.images = [pygame.transform.flip(image, TrueFalsefor image in self.images]
        self.image = self.images[self.index]
 
    def update(self):
        if (camera.offset.x != 0 or camera.offset.y != 0):
                self.rect.move_ip(camera.offset.x, camera.offset.y)
        
        # 1초에 frame번 image 업데이트.
        # self.elapsedTime += clock.get_time()
        # if self.elapsedTime < self.limitTime:
        #     pass
        # else:
        #     self.elapsedTime = 0
        #     self.index += 1
        #     if self.index >= len(self.images):
        #         self.index = 0
        #     self.image = self.images[self.index]
            
def main():
    player = Sprite("character.bmp", (screen.get_width()/2, screen.get_height()/2), 1)
    shop = Sprite("shop.bmp", (screen.get_width()/2, screen.get_height()/2), 1)
    all_sprites = pygame.sprite.Group()
    all_sprites.add(shop)
    all_sprites.add(player)
    
    running = True
    
    while running:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                running = False
            elif event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE:
                running = False
 
        keys = pygame.key.get_pressed()
        if keys[pygame.K_LEFT]:
            if player.direction > 0:
                player.flip_image()
                player.direction = -1
            player.rect.move_ip(-player.speed, 0)            
            
        if keys[pygame.K_RIGHT]:
            if player.direction < 0:
                player.flip_image()
                player.direction = 1
            player.rect.move_ip(player.speed, 0)
        
        if keys[pygame.K_UP]:
            if player.direction < 0:
                player.flip_image()
                player.direction = 1
            player.rect.move_ip(0-player.speed)
        
        if keys[pygame.K_DOWN]:
            if player.direction < 0:
                player.flip_image()
                player.direction = 1
            player.rect.move_ip(0, player.speed)
        
        # 카메라 이동
        if keys[pygame.K_a]:
            camera.offset.x = camera.speed
        if keys[pygame.K_d]:
            camera.offset.x = -camera.speed
        if keys[pygame.K_w]:
            camera.offset.y = camera.speed
        if keys[pygame.K_s]:
            camera.offset.y = -camera.speed
 
        all_sprites.update()
        
        # 스프라이트 업데이트 후 카메라 오프셋 초기화
        camera.offset.x = camera.offset.y = 0        
        
        screen.fill("black")        
        all_sprites.draw(screen)
        pygame.display.flip()
 
        clock.tick(60)
 
    pygame.quit()
 
if __name__ == '__main__':
  main()
 

 

코드를 입력하고 실행한다. set_mode()에 vsync 파라미터를 1로 설정하지 않으면 스프라이트가 움직일때 screen tearing 현상이 일어날 수 있다.

pygame.display.set_mode(..., vsync=1)

 

방향키로 캐릭터를, wasd로 카메라를 움직인다.

 

※ 참고

Cameras in Pygame

 

반응형
Posted by J-sean
:
반응형

파이게임과 GUI 라이브러리를 사용해 보자.

ImGui를 사용해 보려 했는데, OpenGL을 이용해야 하고 pygame.Surface.fill()을 사용할 수 없는 등 마음에 들지 않아 Pygame GUI를 사용하기로 했다.

 

pygame-gui를 설치한다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
import pygame
import pygame_gui
 
pygame.init()
pygame.display.set_caption("Super fun game development")
screenSize = (640480)
screen = pygame.display.set_mode(screenSize, pygame.DOUBLEBUF | pygame.RESIZABLE)
clock = pygame.time.Clock()
 
manager = pygame_gui.UIManager(screenSize)
hello_button = pygame_gui.elements.UIButton(relative_rect=pygame.Rect((1010), (10050)),
                                            text='Say Hello', manager=manager)
 
running = True
 
while running:
    time_delta = clock.tick(60)/1000
    # As you may have noticed we also had to create a pygame Clock to track the amount of time
    # in seconds that passes between each loop of the program. We need this 'time_delta' value
    # because several of the UI elements make use of timers and this is a convenient place to
    # get it.
        
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False
        elif event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE:
            running = False
        
        if event.type == pygame_gui.UI_BUTTON_PRESSED:
              if event.ui_element == hello_button:
                  print('Hello World!')
        
        manager.process_events(event)
    
    manager.update(time_delta)
 
    screen.fill("black")
    pygame.draw.circle(screen, "gray", screen.get_rect().center, 100)
 
    manager.draw_ui(screen)
 
    pygame.display.flip()
 
pygame.quit()
 

 

코드를 입력하고 실행한다.

 

버튼이 표시된다.

 

2024.01.28 - [Python] - [Pygame] Box2D 파이게임 물리 라이브러리

위 링크의 코드를 이용해 조금 더 실용적인 예제를 만들어 보자.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
import math
import pygame
import pygame_gui
from Box2D import *
 
pygame.init()
pygame.display.set_caption("Physics Test")
screen = pygame.display.set_mode((640480))
running = True
player = pygame.image.load("player.png").convert()
 
manager = pygame_gui.UIManager((640480))
again_button = pygame_gui.elements.UIButton(relative_rect=pygame.Rect((35010), (200100)),
                                            text='Play again', manager=manager)
 
world = b2World(gravity=(09.8), doSleep=True)
 
groundBody = world.CreateStaticBody(position=(0400), shapes=b2PolygonShape(box=(5000)))
 
wallBody = world.CreateStaticBody(position=(3000), shapes=b2PolygonShape(box=(0400)))
 
playerBody = world.CreateDynamicBody(position=(00), linearVelocity=(500), angularVelocity=0.2)
playerFixtureDef = playerBody.CreatePolygonFixture(box=(player.get_width()/2,
                              player.get_height()/2), density=1, friction=0.5, restitution=0.7)
 
timeStep = 1.0 / 300
vel_iters, pos_iters = 62
  
while running:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False
        elif event.type == pygame.KEYDOWN and event.key == pygame.K_SPACE:
            playerBody.transform = ((00), 0)
            playerBody.linearVelocity = (500)
            playerBody.angularVelocity = 0.2
        elif event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE:
            running = False
            
        if event.type == pygame_gui.UI_BUTTON_PRESSED:
            if event.ui_element == again_button:
                playerBody.transform = ((00), 0)
                playerBody.linearVelocity = (500)
                playerBody.angularVelocity = 0.2
        
        manager.process_events(event)
            
    manager.update(timeStep)
    
    world.Step(timeStep, vel_iters, pos_iters)
    world.ClearForces()
     
    screen.fill("black")
    pygame.draw.rect(screen, "brown", (040060020))
    pygame.draw.rect(screen, "yellow", (300020400))
 
    rotated_player = pygame.transform.rotate(player, playerBody.angle * 180/math.pi)
    
    screen.blit(rotated_player, (playerBody.position[0- rotated_player.get_width()/2,
                                 playerBody.position[1- rotated_player.get_height()/2))
 
    manager.draw_ui(screen)
    
    pygame.display.flip()
    
pygame.quit()
 

 

코드를 입력하고 실행한다.

 

버튼을 클릭하면 캐릭터가 다시 던져진다.

 

※ 참고

GUIs with pygame

Pygame GUI

 

반응형
Posted by J-sean
:
반응형

파이게임과 2D Rigid Body Simulation Library Box2D를 사용해 보자.

 

다음 명령어로 Box2D를 설치한다.

pip install box2d

 

설치중 에러가 발생한다면 SWIG를 설치하고 설치 디렉토리를 시스템 변수 Path에 등록한다.

SWIG

 

SWIG를 설치하면 에러가 발생하지 않는다.

 

추가로 box2d-kengz를 설치한다.

 

player.png
0.00MB

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
import math
import pygame
from Box2D import *
 
pygame.init()
pygame.display.set_caption("Physics Test")
screen = pygame.display.set_mode((640480))
running = True
player = pygame.image.load("player.png").convert()
 
# World 정의
world = b2World(gravity=(09.8), doSleep=True)
 
# Ground 정의
groundBodyDef = b2BodyDef()
groundBodyDef.position = (0400)
groundBody = world.CreateBody(groundBodyDef)
groundShape = b2PolygonShape()
groundShape.SetAsBox(5000)
groundBody.CreateFixture(shape=groundShape)
#groundBody = world.CreateStaticBody(position=(0, 400), shapes=b2PolygonShape(box=(500, 0)))
# 위 정의와 동일
 
# Wall 정의
wallBodyDef = b2BodyDef()
wallBodyDef.position = (3000)
wallBody = world.CreateBody(wallBodyDef)
wallShape = b2PolygonShape()
wallShape.SetAsBox(0400)
wallBody.CreateFixture(shape=wallShape)
#wallBody = world.CreateStaticBody(position=(300, 0), shapes=b2PolygonShape(box=(0, 400)))
# 위 정의와 동일
 
# Player 정의
playerBodyDef = b2BodyDef()
playerBodyDef.type = b2_dynamicBody;
playerBodyDef.position = (00)
playerBodyDef.linearVelocity = (500)
playerBodyDef.angularVelocity = 0.2
playerBody = world.CreateBody(playerBodyDef)
playerShape = b2PolygonShape()
playerShape.SetAsBox(player.get_width()/2, player.get_height()/2)
playerFixtureDef = b2FixtureDef(shape=playerShape)
playerFixtureDef.density = 1
playerFixtureDef.friction = 0.5
playerFixtureDef.restitution = 0.7
playerBody.CreateFixture(playerFixtureDef)
#playerBody = world.CreateDynamicBody(position=(0, 0), linearVelocity=(50, 0),
#                                     angularVelocity=0.2)
#playerFixtureDef = playerBody.CreatePolygonFixture(box=(player.get_width()/2,
#                          player.get_height()/2), density=1, friction=0.5, restitution=0.7)
# 위 정의와 동일
 
timeStep = 1.0 / 300
vel_iters, pos_iters = 62
  
while running:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False
        elif event.type == pygame.KEYDOWN and event.key == pygame.K_SPACE:
            playerBody.transform = ((00), 0)
            playerBody.linearVelocity = (500)
            playerBody.angularVelocity = 0.2
        elif event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE:
            running = False
    
    # Instruct the world to perform a single step of simulation. It is
    # generally best to keep the time step and iterations fixed.
    world.Step(timeStep, vel_iters, pos_iters)
    # Clear applied body forces. We didn't apply any forces, but you
    # should know about this function.
    world.ClearForces()
     
    screen.fill("white")
    pygame.draw.rect(screen, "brown", (040060020)) # Ground 그리기
    pygame.draw.rect(screen, "black", (300020400)) # Wall 그리기
 
    rotated_player = pygame.transform.rotate(player, playerBody.angle * 180/math.pi)
    # Unless rotating by 90 degree increments, the image will be padded larger to hold
    # the new size. If the image has pixel alphas, the padded area will be transparent.
    # Otherwise pygame will pick a color that matches the Surface colorkey or the topleft
    # pixel value.
    screen.blit(rotated_player, (playerBody.position[0- rotated_player.get_width()/2,
                                 playerBody.position[1- rotated_player.get_height()/2))
 
    pygame.display.flip()
    
pygame.quit()
 

 

코드를 입력하고 실행한다.

 

GIF 캡쳐 과정에서 화질이 많이 떨어졌지만 강체들의 물리 반응을 확인할 수 있다.

 

pygame.transform.rotate()

rotate an image
rotate(surface, angle) -> Surface

Unfiltered counterclockwise rotation. The angle argument represents degrees and can be any floating point value. Negative angle amounts will rotate clockwise.
Unless rotating by 90 degree increments, the image will be padded larger to hold the new size. If the image has pixel alphas, the padded area will be transparent. Otherwise pygame will pick a color that matches the Surface colorkey or the topleft pixel value.

 

배경을 바꾸거나 Colorkey를 설정하면 캐릭터 주변 패딩을 없앨 수 있다.

 

아래 링크에서 GUI를 구현해 본다.

2024.01.29 - [Python] - [Pygame] Pygame GUI 파이게임 그래픽 유저 인터페이스

 

※ 참고

PyBox2D

PyBox2D Manual

 

반응형
Posted by J-sean
:
반응형

충돌 감지 영역을 원으로 지정하고 스프라이트 충돌을 확인해 보자.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
import pygame
 
pygame.init()
pygame.display.set_caption("Super fun game development")
screen = pygame.display.set_mode((640480))
clock = pygame.time.Clock()
 
class Player(pygame.sprite.Sprite):
    def __init__(self, position):
        pygame.sprite.Sprite.__init__(self)
 
        self.direction = -1
        self.speed = 4
        self.image = pygame.image.load("player.png").convert()
        self.image.set_colorkey(self.image.get_at((00)))
        self.size = (self.image.get_width()*1.5self.image.get_height()*1.5)
        self.image = pygame.transform.scale(self.image, self.size)
        self.rect = self.image.get_rect(center=position)
        # rectangle이 아닌 circle을 이용해 충돌 감지하기 위한 반지름 속성 설정.
        self.radius = 40
        # 충돌 감지 circle 표시
        pygame.draw.circle(self.image, "red"self.image.get_rect().center, self.radius, 2)
 
    def flip_image(self):
        self.image = pygame.transform.flip(self.image, TrueFalse)
        
    def update(self):
        pass
# 플레이어 클래스
 
class Bubble(pygame.sprite.Sprite):
    def __init__(self, position):
        pygame.sprite.Sprite.__init__(self)
 
        self.image = pygame.image.load("bubble.png").convert()
        self.image.set_colorkey(self.image.get_at((00)))
        self.size = (self.image.get_width()*6self.image.get_height()*6)
        self.image = pygame.transform.scale(self.image, self.size)
        self.rect = self.image.get_rect(center=position)
        self.collided = False
        # rectangle이 아닌 circle을 이용해 충돌 감지하기 위한 반지름 속성 설정.
        self.radius = 40
        # 충돌 감지 circle 표시
        pygame.draw.circle(self.image, "red"self.image.get_rect().center, self.radius, 2)
 
    def update(self):
        if self.collided == True:
            self.rect.top -= 1
# 버블 클래스
# 충돌(self.collided)을 감지하면 위치(self.rect.top)가 변한다.
 
def main():
    player = Player((screen.get_width()/2, screen.get_height()/2))
    player_sprite = pygame.sprite.Group(player)
    # 플레이어 스프라이트 그룹
 
    bubbles = [
        Bubble((40, screen.get_height()/2)),
        Bubble((160, screen.get_height()/2)),
        Bubble((480, screen.get_height()/2)),
        Bubble((600, screen.get_height()/2))]
    bubble_sprites = pygame.sprite.Group(bubbles)
    # 버블 스프라이트 그룹
 
    running = True
 
    while running:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                running = False
            elif event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE:
                running = False
 
        keys = pygame.key.get_pressed()
        if keys[pygame.K_LEFT]:
            if player.direction > 0:
                player.flip_image()
                player.direction = -1
            player.rect.move_ip(-player.speed, 0)
        if keys[pygame.K_RIGHT]:
            if player.direction < 0:
                player.flip_image()
                player.direction = 1
            player.rect.move_ip(player.speed, 0)
 
        # spritecollide()의 마지막 인수 collided에 collide_circle()를 대입한다.
        collision = pygame.sprite.spritecollide(player, bubble_sprites, False, pygame.sprite.collide_circle)
        for bubble in collision:
            bubble.collided = True
        # 플레이어와 버블의 충돌을 감지하고 충돌한 버블의 collided 값을 True로 바꾼다.
        
        player_sprite.update()
        bubble_sprites.update()
                 
        screen.fill("black")
         
        player_sprite.draw(screen)
        bubble_sprites.draw(screen)
    
        pygame.display.flip()
        clock.tick(60)
 
    pygame.quit()
 
if __name__ == '__main__':
  main()
 

 

 

공룡과 버블의 충돌 감지 영역이 빨간 원으로 표시된다.

 

좀 더 확실한 확인을 위해 공룡과 버블의 충돌 감지 circle의 radius를 20으로 바꾸고 다시 실행해 보자.

 

스프라이트는 충돌 했지만 원은 충돌하지 않았기 때문에 충돌로 판정되지 않는다.

 

 

반응형
Posted by J-sean
:
반응형

사방이 벽으로 둘러쌓인 공간에서 이리저리 움직이는 공을 만들어 보자.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
import pygame
 
pygame.init()
pygame.display.set_caption("Super fun game development")
screen = pygame.display.set_mode((640480))
clock = pygame.time.Clock()
 
position = pygame.math.Vector2(screen.get_width()/2, screen.get_height()/2)
velocity = pygame.math.Vector2(11).normalize() * 5
 
running = True
 
while running:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False
        elif event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE:
            running = False
 
    screen.fill("black")
 
    if position.y > screen.get_height():
        velocity.reflect_ip(pygame.math.Vector2(01))
        # 천장이나 바닥에 부딪히면 (0, 1)의 법선 백터를 갖는 평면에 반사.
    elif position.y < 0:
        velocity.reflect_ip(pygame.math.Vector2(01))
    elif position.x > screen.get_width():
        velocity.reflect_ip(pygame.math.Vector2(10))
        # 오른쪽이나 왼쪽에 부딪히면 (1, 0)의 법선 백터를 갖는 평면에 반사.
    elif position.x < 0:
        velocity.reflect_ip(pygame.math.Vector2(10))  
 
    position = position + velocity
    pygame.draw.circle(screen, "red", position, 20)
    pygame.display.flip()
 
    clock.tick(60)
 
pygame.quit()
 

 

 

 

반응형
Posted by J-sean
: