본문 바로가기
개발 일지

파이썬 tkinter 그래픽으로 슈팅 게임 만들기 4

by PrintedLove 2019. 11. 24.

소스 코드입니다.

 

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
from tkinter import *
import time
import math
 
window = Tk()
window.title("nemoRPG")   # 게임 이름
window.resizable(0,0)
canvas = Canvas(window, width = 640, height = 640, bg ="white")   # 창 생성
 
class Game:   # 게임 클래스
    global objects
    objects = set()   # 오브젝트 세트 생성
    def __init__(self):
        self.keys = set()   # 버튼 세트 생성
        self.mx, self.my, self.mPressed = 000   # 마우스 좌표, 클릭 여부
        window.bind("<KeyPress>", self.keyPressHandler)   # 버튼 클릭시 함수호출
        window.bind("<KeyRelease>", self.keyReleaseHandler)   # 버튼 땔시 함수호출
        canvas.bind("<Button-1>", self.mousePress)   # 마우스 클릭시 함수호출
        canvas.bind("<B1-Motion>", self.mousePress)
        canvas.bind("<ButtonRelease-1>", self.mouseRelease)   # 마우스 땔시 함수호출
        canvas.pack()
 
        obj_main = object_main(3103102020"black")   # main 오브젝트 생성
 
        while(1):  # 메인 루프
            for key in self.keys:   # 버튼 체킹    
                if obj_main in objects:
                    if key == ord('A'and obj_main.x_accel > -4:   # A
                        obj_main.x_accel -= 1
                    if key == ord('D'and obj_main.x_accel < 4:   # D
                        obj_main.x_accel += 1
                    if key == ord('W'and obj_main.y_accel > -4:   # W
                        obj_main.y_accel -= 1
                    if key == ord('S'and obj_main.y_accel < 4:   # S
                        obj_main.y_accel += 1
 
            if self.mPressed == 1:   # 마우스 클릭 시
                obj_attack = object_attack(canvas.coords(obj_main.canvas_id)[0]+8, canvas.coords(obj_main.canvas_id)[1]+844"black"120)
                obj_attack.x_accel, obj_attack.y_accel = self.movePoint(canvas.coords(obj_attack.canvas_id)[0+ 10, canvas.coords(obj_attack.canvas_id)[1+ 10, self.mx, self.my, 25)
 
            for obj in objects.copy():   # 오브젝트 스텝
                obj.step()
                    
            window.update()   # 업데이트
            time.sleep(0.01)   # 0.01초 만큼 sleep
                        
    def keyPressHandler(self, event):   # 버튼 세트에 버튼추가
        self.keys.add(event.keycode)
 
    def keyReleaseHandler(self, event):   # 버튼 세트에 버튼 제거
        if event.keycode in self.keys:
            self.keys.remove(event.keycode)
 
    def mousePress(self, event):   # 마우스 왼쪽 누를시 좌표 반환, 클릭값 1
        self.mx, self.my, self.mPressed = event.x, event.y, 1
 
    def mouseRelease(self, event):   # 마우스 왼쪽 땔시 좌표 반환, 클릭값 0
        self.mx, self.my, self.mPressed = event.x, event.y, 0
 
    def movePoint(self, x1, y1, x2, y2, spd):   # 해당 좌표로 이동
        distance = math.sqrt((x2 - x1) ** 2 + (y2 - y1) ** 2)
        if spd < distance:
            return (x2 - x1) * spd / distance, (y2 - y1) * spd / distance
        else:
            return 00
 
class element:   # 오브젝트 원형
    def __init__(self, x, y, size_x, size_y, color):
        self.x, self.y = x, y   # 생성 위치
        self.size_x, self.size_y = size_x, size_y   # 크기
        self.color = color   # 색
        self.x_accel, self.y_accel = 00   # 가속도
        objects.add(self)   # 오브젝트 세트에 자신 등록
        self.canvas_id = canvas.create_rectangle(x, y, x + self.size_x, y + self.size_y, fill = self.color, width =0)   # 캠버스 추가
 
    def destroy(self):   # 제거 함수
        objects.discard(self)   # 오브젝트 세트에서 자신 제거
        canvas.delete(self.canvas_id)   # 캠버스 제거
        del self
 
    def move(self):   # 움직임 계산(이동, 가속도, 중력) 함수
        x_value, y_value = self.x_accel, self.y_accel
        if x_value != 0 or y_value != 0:   # 좌표 갱신
            if canvas.coords(self.canvas_id)[0+ x_value < 0:
                x_value = -canvas.coords(self.canvas_id)[0]   # 창나감 방지
                self.x_accel = -self.x_accel   # 튕김
            if canvas.coords(self.canvas_id)[1+ y_value < 0:
                y_value = -canvas.coords(self.canvas_id)[1]
                self.y_accel = -self.y_accel
            if canvas.coords(self.canvas_id)[2+ x_value > 640:
                x_value = 640 - canvas.coords(self.canvas_id)[2]
                self.x_accel = -self.x_accel
            if canvas.coords(self.canvas_id)[3+ y_value > 640:
                y_value = 640 - canvas.coords(self.canvas_id)[3]
                self.y_accel = -self.y_accel
            canvas.move(self.canvas_id, x_value,  y_value)   # 수치만큼 이동
            self.mx, self.my = 00   # 이동값 초기화
            self.x_accel -= self.x_accel/50   # 가속도 감소
            self.y_accel -= self.y_accel/50
 
class object_main(element):   # main 오브젝트
    def __init__(self, x, y, size_x, size_y, color):
        super().__init__(x, y, size_x, size_y, color)   # 상속
        self.mhp, self.hp = 10001000   # 체력
        self.cool, self.coolt = 250   # 쿨타임
 
    def step(self):   # 스텝 함수
        self.move()
        if self.coolt < self.cool:  # 쿨타임 감소
            self.coolt += 1 
 
class object_attack(element):   # attack 오브젝트
    def __init__(self, x, y, size_x, size_y, color, livetime):
        super().__init__(x, y, size_x, size_y, color)   # 상속
        self.livetime = livetime   # 동작 시간
        self.fortime = 0   # 지난 시간
 
    def step(self):   # 스텝 함수
        self.move()
        if self.livetime <= self.fortime:   # 동작 시간 오버 or 멈출시 파괴
            self.destroy()
        self.fortime += 1    # 지난 시간 ++
 
Game()   # 게임 실행
cs

 

 마우스 클릭시 해당 방향으로 투사체가 날아가도록 공격 오브젝트를 구현했습니다.

 점으로 이동을 위해 math 라이브러리를 import 했고, 마우스 좌표와 클릭 여부를 저장하는 지역변수를 선언했습니다.

 

 아, 그리고 canvas를 가르키는 id 변수 이름이 함수이름과 겹친다고 교수님께서 지적하셔서 id 변수 이름을 canvas_id로 변경했습니다(중요).

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class object_main(element):   # main 오브젝트
    def __init__(self, x, y, size_x, size_y, color):
        super().__init__(x, y, size_x, size_y, color)   # 상속
        self.mhp, self.hp = 10001000   # 체력
        self.cool, self.coolt = 250   # 쿨타임
 
    def step(self):   # 스텝 함수
        self.move()
        if self.coolt < self.cool:  # 쿨타임 감소
            self.coolt += 1 
 
class object_attack(element):   # attack 오브젝트
    def __init__(self, x, y, size_x, size_y, color, livetime):
        super().__init__(x, y, size_x, size_y, color)   # 상속
        self.livetime = livetime   # 동작 시간
        self.fortime = 0   # 지난 시간
 
    def step(self):   # 스텝 함수
        self.move()
        if self.livetime <= self.fortime:   # 동작 시간 오버 or 멈출시 파괴
            self.destroy()
        self.fortime += 1    # 지난 시간 ++
cs

 

코드의 밑부분을 잘 보시면 못보던 클래스가 생긴 것을 알 수 있습니다.

element클래스를 부모로 두개의 클래스를 새로 선언 한 것인데요.

 

element클래스의 물리엔진 함수를 그대로 사용하면서 용도에 맞게(유저, 투사체) 사용하기 위해서입니다.

main 오브젝트에는 HP변수와 쿨타임을, attack 오브젝트에는 동작시간 변수가 따로 선언했습니다.

 

메인 루프에서 매번 호출되는 step 함수도 각각 따로 선언해 main 오브젝트는 쿨타임을 관리하고, attack 오브젝트는 일정 시간이 지나면 소멸하도록 설정 했습니다.

 

 

 

다음 글에서는 HP 바와 점수, 공격 쿨타임을 추가해 보도록 하겠습니다

댓글