안녕하세요.

 

일단 지난시간에 짜놓은 코드를 봅시다.

 

블루슬라임 클래스는 슬라임 클래스의 어택 함수를 상속받아서 소유하고 있습니다. 인간의 체력을 10감소시킵니다. 

그런데 블루슬라임은 체력회복 스킬도 있으니 좀 밸런스가 맞지 않는다는 느낌이 들어서 어택 함수를 좀 약하게 수정하고 싶습니다. 그렇다고 해서 슬라임 클래스의 어택함수를 수정하게 되면 모든 종류의 슬라임이 영향을 받게 되는 문제가 생깁니다. 다른 종류의 슬라임에는 영향이 안가고 블루슬라임만 공격력을 낮추고 싶을 땐 어떻게 하면 될까요?

 

아래를 보시죠.

 

답은 간단합니다. 블루슬라임 클래스에다가도 어택 함수를 만들어주고 적절한 내용을 적어주면 되는거죠. (인간의 체력을 8 감소시키도록 했습니다)

 

이처럼 자식 클래스 속에 부모 클래스로부터 상속받은 함수를 일부러 적어서 내용을 바꾸는 것을 오버라이드라고 합니다. 이렇게 되면 해당함수를 실행했을때 자식 클래스의 함수가 실행됩니다.(어택 함수 실행시 체력 8 감소) 오버라이드된 함수가 더 우선인거죠. (오버라이드의 사전적 의미를 찾아보면 "우선하다"라는 뜻이 있습니다.)

 

오버라이드... 우선하다... 잘 안외워지신다구요? '오버라이드는 오버라이트(over write. 덮어쓰기) 같은 거다' 는 어떤가요? 부모 클래스의 함수를 자식 클래스의 함수가 덮어쓰는거죠.

 

47행의 행번호 왼쪽에 초록색 삼각형 보이시나요? 오버라이드된 함수라는 표시입니다.

 

 

오버라이드된 함수는 위의 47행 처럼 함수문장 위에 @오버라이드 라고 적어주는게 좋습니다. 오버라이드 되었다는 것을 좀 더 명확하게 알 수 있죠. 그리고 한가지 순기능이 더 있는데 예를들면,

 

 

위에 처럼 실수로 attack의 t를 하나 빼먹은채로 함수를 만들었다고 칩시다. 이렇게 되면 블루슬라임은 attack 함수도 가지고 있고 atack함수도 가지고 있는 상태가 됩니다. 개발자는 메인함수에서 bs1.attack(h1)라고 적었는데 인간의 체력이 10 깎이는 걸 보고 혼란속에 빠지게 되는 상황이 벌어질 수 있습니다.

 

 

하지만 위에처럼 @오버라이드 라고 해놓으면 함수 이름이 잘못되었을 때 에러라고 표시를 해줍니다. 부모 클래스에 atack이라는 함수가 없으므로 오버라이드 할 수 없다는 에러죠.

감사합니다.


안녕하세요


지난시간에 이런 의문이 들 수 있다고 말씀드렸었죠.


"클래스를 바로 만들면 되지 굳이 부모 클래스부터 만들어서 상속받을 필요가 있는가?"


아래 예시를 통해 의문을 해소해 봅시다. 


부모가 되는 슬라임 클래스 없이 레드슬라임, 블랙슬라임, 옐로우 슬라임 클래스를 바로 만들었습니다.




딱 봐도 중복되는 내용이 많아서 시간 낭비 + 라인 낭비라는 느낌이 드시죠? ㅎ


hp, str, def, dex 변수와 attack, runAway 함수는 공통되는 부분이기 때문에 부모가 되는 슬라임 클래스를 만들어서 거기다가 집어넣으면 되겠습니다.


만약 hp를 200으로 수정해야될경우, 부모 클래스가 있다면 부모 클래스의 hp만 수정하면 된다는 이점도 있죠^^


감사합니다.


안녕하세요.


지난시간에 상속에 대한 개념을 잡았으니 이번 시간에는 기존의 슬라임 클래스를 상속받은 블루슬라임 클래스를 만들어보도록 하겠습니다.




자, 설명 들어갈게요.


생성자는 지난시간하고 동일하니 또 설명 안드려도 될 것 같네요.


생성자 아래에 치료함수를 추가해줬습니다. 인수로 슬라임을 지정해서 자기 자신을 포함한 모든 슬라임을 치료할 수 있도록 했습니다. (만약 슬라임 대신에 블루슬라임을 넣으면 나중에 만들 예정인 '레드슬라임'은 치료가 불가능해집니다)


47행의 조건문은 자신의 체력과 치료받을 슬라임의 체력이 모두 0보다 커야된다는 조건입니다.


그리고 51행의 조건문은 치료후의 체력이 80을 넘으면 원래 체력을 초과해버리는 것이기 때문에 80으로 재조정하는 내용입니다.



이제 메인클래스에서 블루슬라임을 사용해봐야겠죠?



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
// Study01.java
 
package study;
 
import java.awt.Font;
import java.util.Enumeration;
 
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.UIManager;
import javax.swing.plaf.FontUIResource;
 
public class Study01 {
 
    // 라벨 변수 선언
    static JLabel lbl, lbl2;
 
    // ★ 슬라임과 인간 객체 생성
    static BlueSlime bs1 = new BlueSlime("슬라삐");
    static BlueSlime bs2 = new BlueSlime("슬라디");
    static Human h = new Human("알렉스");
 
    public static void main(String[] args) {
 
        // [start] 디자인 코드
 
 
        // 모든 글꼴 통일
        Enumeration<Object> keys = UIManager.getDefaults().keys();
        while (keys.hasMoreElements()) {
            Object key = keys.nextElement();
            Object value = UIManager.get(key);
            if (value instanceof FontUIResource)
                UIManager.put(key, new FontUIResource("굴림", Font.PLAIN, 14));
        }
 
        // [start] 프레임 설정
        JFrame frm = new JFrame();
        frm.setTitle("슬라임 퇴치하기");
        frm.setSize(350350);
        frm.setLocationRelativeTo(null);
        frm.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frm.getContentPane().setLayout(null);
        // [end] 프레임 설정
 
        // [start] ★ 버튼 설정
        JButton btn1 = new JButton(bs1.name);
        JButton btn2 = new JButton(bs2.name);
        btn1.setBounds(3017012230);
        btn2.setBounds(18217012230);
        frm.getContentPane().add(btn1);
        frm.getContentPane().add(btn2);
        // [end] 버튼 설정
 
        // 라벨 설정
        lbl = new JLabel();
        lbl.setBounds(3021027450);
        lbl.setText("게임을 시작합니다");
        lbl.setHorizontalAlignment(JLabel.CENTER); // 수평 가운데 정렬
        frm.getContentPane().add(lbl);
 
        // 라벨2 설정
        lbl2 = new JLabel();
        lbl2.setBounds(3024027450);
        lbl2.setText(h.name + "의 체력은 " + h.hp + "입니다");
        lbl2.setHorizontalAlignment(JLabel.CENTER); // 수평 가운데 정렬
        frm.getContentPane().add(lbl2);
 
        // [start] 이미지 라벨 생성
        JLabel imgLbl = new JLabel();
        ImageIcon bsImg = new ImageIcon(Study01.class.getResource("/study/img/slime(blue).png"));
        imgLbl.setIcon(bsImg);
        imgLbl.setBounds(3030122130);
        imgLbl.setHorizontalAlignment(JLabel.CENTER);
        frm.getContentPane().add(imgLbl);
        // [end]
 
        // [start] 이미지 라벨2 생성
        JLabel imgLbl2 = new JLabel();
        imgLbl2.setIcon(bsImg);
        imgLbl2.setBounds(18230122130);
        imgLbl2.setHorizontalAlignment(JLabel.CENTER);
        frm.getContentPane().add(imgLbl2);
        // [end]
 
        // 프레임이 보이도록 설정
        frm.setVisible(true);
 
        // [end]
 
        // ★ 버튼을 눌렀을때
        btn1.addActionListener(event -> {
 
            battle(bs1);
 
        });
 
        btn2.addActionListener(event -> {
 
            battle(bs2);
 
        });
 
    }
 
    public static void battle(BlueSlime bs) {
 
        // ★ 슬라임이 살아있을때만 공격
        if (bs.hp < 1) {
 
            lbl.setText(bs.name + "는 이미 죽어있다\n");
 
        } else {
 
            h.attack(bs);
            bs.heal(bs);
 
        }
 
        // ★ 슬라임이 모두 죽으면 게임 클리어
        if (bs1.hp < 1 && bs2.hp < 1) {
 
            JOptionPane.showMessageDialog(lbl2, "Game Clear!");
            System.exit(0);
        }
 
    }
 
}
 
cs


이렇게 되겠죠. s, s1, s2 앞에 모두 b가 붙은 점 유의해주세요.


이제 실행해봅시다.




치료함수가 잘 작동되는군요^^


근데 한가지 의문이 드는 분들이 계실지 모르겠습니다. 애초에 블루슬라임 클래스를 바로 만들어서 name부터 heal까지 다 설계해놓으면 될것을, 굳이 번거롭게 슬라임 클래스부터 먼저 만들어서 상속받게 해놓을 필요가 있는가... 하는 의문요.


다음시간에는 이 의문을 풀어보겠습니다.


감사합니다.



안녕하세요.


이번 시간 진도를 나가기 전에 예를 한가지 들겠습니다.


부모가 있고 자식이 있습니다. 부모는 자식에게 집안의 문화, 가치관, 밥상예절, 지식을 물려줍니다(상속해줍니다). 권력이 있는 집안이라면 권력도 물려줍니다. 자식은 자라면서 그러한 물려받는 것 외에 자신만의 것을 습득하여 부모보다 더 나은 사람이 됩니다.


갑자기 이런 예를 든 이유는 3탄에서 기존의 '슬라임'클래스를 물려받은(상속받은) '블루슬라임'클래스를 만들어볼 것이기 때문입니다. 슬라임 클래스가 부모의 위치고 블루슬라임 클래스가 자식의 위치입니다. 자식 클래스는 부모 클래스의 변수와 메서드를 상속받아서 기본적으로 가지고 있습니다. 거기다가 추가적으로 자신만의 변수나 메서드를 가질 수 있습니다. (상속의 예로, 돈 같은 물질이 아니라 무형 자산을 예로 든 이유는 물질은 부모가 자식에게 상속해주는 순간 부모는 그것을 잃게 되기 때문입니다. 부모 클래스가 자식 클래스에게 변수와 메서드를 상속해 주는 것은 그것을 '복사'해주는 것이기 때문에 무형 자산을 예로 드는게 더 적합해 보입니다. 그리고 현실세계의 상속은 부모가 사망시에 일어나지만 클래스의 경우에는 사망과는 무관합니다.)


블루슬라임 클래스를 만들기 전에 간단한 거 하나 만들어보고 진행합시다.




자, 지난시간에 만들었던 horse 클래스를 살짝 수정했습니다. 이름 변수를 가지고 있고, 생성자는 받아온 이름을 이름 변수에 넣는 내용이고, 달리는 함수가 있네요.


이제 이 클래스를 부모로 하여 자식 클래스를 만들어보겠습니다. 부모-자식이라고 해서 두 클래스 사이에 혈연관계가 있어야 될 필요는 없습니다. 사실, 부모-자식 보다는 오리지날-확장이 더 어울리는 경우가 많습니다. 아래를 보시죠.




여태까지는 java파일 하나에 클래스 하나씩 만들어줬는데 사실은 여러 클래스를 만들어줄 수 있습니다. (단, 두번째 클래스부터는 앞에 public이 붙으면 안됩니다)


빨간테두리를 보시면 유니콘 클래스가 코딩되어 있습니다.


21행부터 보시죠.



class 자식 클래스 extends 부모 클래스



이런 형태입니다. extend의 뜻은 확장인데 자식 클래스는 부모 클래스에다가 변수나 메서드를 추가하여 클래스를 확장시킨다는 의미에서 확장입니다. 영어를 해석하면 '클래스 유니콘은 확장한다 말을' 이렇게 되겠네요.


25-27행은 생성자군요. 생성자는 상속이 되지 않기 때문에 적어줘야 합니다. 근데 생성자 내용이 name = n 이 아니네요?!



super(n)



새로운 단어가 등장했네요. 사실, 자식 클래스의 생성자는 무조건 부모 클래스의 생성자를 호출해야된다는 법칙이 있습니다. 


지난시간에 같은 클래스 내의 다른 생성자 호출할때 this()를 썼었죠? 부모 클래스의 생성자를 호출할때는 super()를 사용합니다.


자식 입장에서 부모님은 슈퍼맨처럼 보이잖아요?ㅎ


인수에다가 이름을 넣어주면 최종적으로 name 변수에 들어갑니다.



자, 여기서 퀴즈 하나 내겠습니다. 유니콘 클래스가 가지고 있는 변수와 함수를 모두 열거해보세요~


fp 변수와 생성자 함수와 비행 함수 밖에 없다구요? 노노. 눈에 보이진 않지만 부모로부터 상속받은 name 변수와 달리기 함수도 갖고 있습니다^^




정말 그렇죠? ㅎ


다음 시간에는 블루슬라임 클래스를 만들어보겠습니다.


감사합니다.


안녕하세요.


슬라임 퇴치 게임 3탄에서는 슬라임의 종류를 다양화할건데요, 그러기 위해서는 상속에 대해 알아야되고 상속을 이해하려면 생성자에 대해 조금더 깊이 알아야됩니다.


이번 강좌에서는 '생성자 오버로딩'이란 개념에 대해 배워보겠습니다. 용어가 좀 생소한데요, 알고보면 별거 아닙니다. 아래 예제를 보시죠.



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// Horse.java
 
package study;
 
public class Horse {
 
    Horse(int i) {
 
        System.out.println(i + "킬로그램의 말이 탄생했습니다");
 
    }
 
    Horse(int i, String str) {
 
        System.out.println(i + "킬로그램의 " + str + "라는 이름의 말이 탄생했습니다");
 
    }
 
}
 
cs


Horse(말)라는 클래스를 만들고 생성자를 2개 만들었습니다. (생성자 앞에 public이 빠졌는데 에러가 나지 않으므로 넘어갑시다. 훗날 public을 반드시 붙여야 하는 경우가 발생하면 그때 public에 대해 설명드리겠습니다)


생성자는 무조건 하나만 만들어야 되는줄 아셨겠지만 이렇게 여러개 만들 수 있습니다^^


이렇게 만들어두면 어떤 상황이 발생하는지 Study02로 가서 객체를 생성해봅시다.




어떤가요? ㅎㅎ


생성자의 인수로 정수값 하나만 넣어주면 첫번째 생성자가 호출되고, 정수값과 문자값을 같이 넣어주면 두번째 생성자가 호출됨을 알 수 있습니다.


다시말해서, 생성자의 인수에 따라서 그에 맞는 생성자가 호출이되는 것이죠.


이것을 '생성자 오버로딩'이라고 합니다. 오버로딩(overloading)은 '과적'이라는 뜻인데 동일한 이름의 함수를 인수 구성만 달리해서 여러개 만들어서 사용하는 기법입니다. 똑같은 함수가 여러개 있으니 '과해'보이긴 하네요 ㅎㅎ 그렇다고 해서 사용을 자제해야된다는 건 아니기 때문에 안심하세요^^



자, 이번엔 더 신기한걸 보여드릴게요.




신기방기^^


horse 클래스의 9행이 엄청엄청 중요합니다.



생성자 속에서 같은 클래스의 다른 생성자를 호출하고 싶을때는 this()를 사용합니다.



자, 실행순서를 차근차근 따라가봅시다.


우리가 실행명령을 내리면 컴퓨터는 우선 스터디02 클래스의 9행을 처리하겠죠.


생성자에 정수값만 적혀있으니 horse클래스의 첫번째 생성자를 호출합니다.


그런데 첫번째 생성자의 내용을 보니 메인함수에서 받아온 정수값과 "마순이"라는 문자값을 이용해서 두번째 생성자를 호출하는군요?


따라서 최종적으로 horse클래스의 15행이 실행이 되는 것입니다.



자, 이해가 되셨으면 다음 강의로 넘어가시면 됩니다.


다음 시간에는 '상속'에 대해 배워보겠습니다.


감사합니다.


안녕하세요.


이제 사소한 버그 2개만 잡으면 2탄 완성입니다.




먼저, 슬라임이 죽었을때 아래쪽 메세지가 남아있는 버그가 있었죠.







간단합니다. 20행을 추가해주면 되겠죠. 따옴표 속에 아무것도 안적으면 공백이 세팅됩니다.





그리고 이미 죽어있는 슬라임을 공격했을때 죽어있다는 메세지가 콘솔창에 출력되는 것도 수정합시다.



// Study01.java





이제 다른 버그는 없어보이는군요^^


그런데... 게임 클리어 메세지가 슬라임 그림을 가려버리니 개인적으로 마음에 들지 않네요.


그래서 메세지박스 위치를 아래로 좀 옮겨볼까 합니다.


무조건 화면 정중앙에 뜨는줄만 알았던 메세지박스. 사실은 위치를 지정할 수 있습니다^^



JOptionPane.showMessageDialog(위치 기준, 메세지);



첫번째 인수는 그냥 무조건 null로 적어야 되는줄 아셨겠지만 null은 위치 기준을 지정하지 않겠다는 뜻이었습니다. 지정하지 않으면 화면정중앙에 뜨도록 되어 있죠.


그렇다고해서 위치 기준에다가 좌표값을 넣으면 안됩니다. 메세지박스 함수의 설명을 살펴보면 컴포넌트를 넣으라고 돼있습니다. 버튼이나 라벨 같은거 말이죠. 박스를 아래쪽에다가 표시하고 싶으니까 아래쪽에 배치되어있는 lbl2 컴포넌트를 집어넣어봅시다.



// Study01.java


실행해봅시다^^






짠~ 이렇게 뜹니다^^ lbl2의 중심좌표와 메세지박스의 중심좌표가 일치합니다.



Human.txt

Slime.txt

Study01.txt



이렇게해서 2탄이 완성되었습니다. 2탄에서는 게임을 GUI 방식으로 구현하는데 중점을 두었습니다. 게임에다가 재미요소를 추가시키는 것은 3탄에서 해야겠네요^^ 그럼, 3탄에서 뵙도록 하죠.


감사합니다.


안녕하세요.


이번시간에는 전투가 진행중일때 메세지를 라벨에다가 표시하도록 하겠습니다.





// Study01.java


실질적으로 전투가 일어나는 시점은 118행의 어택함수가 호출되는 시점입니다. 휴먼 클래스에 있으니까 휴먼 클래스로 가봅시다.







기존에는 System.out.println이었는데 라벨에 표시를 해야되니 라벨에 글자를 설정하는 코드로 수정했습니다.


lbl 변수가 Study01 클래스에 있지만 Study01 다음에 점을 찍었을때 나타나지 않습니다. 억지로 적어도 빨간 밑줄이 붙네요.



클래스명.변수



이런 형태로 사용하기 위해서는 변수가 전역변수여야하고 앞에 static이 붙어있어야 됩니다. (예전에 배운 기억을 더듬어 보시길 ㅎ)






이런식으로 라벨 변수를 밖으로 꺼낸 뒤 static을 붙였습니다. 이렇게 하면 휴먼 클래스의 에러가 사라지는 걸 볼 수 있습니다.


이제 슬라임 클래스도 수정해봅시다.






이렇게 하면 되겠죠. lbl2인 점에 주의하시구요.


이제 실행해봅시다.







잘 나오는군요^^


그런데 말입니다...






슬라삐가 사망했을때 lbl2에는 예전 메세지가 그대로 남아있네요.


다음 시간에는 이러한 자잘한 버그들을 고쳐보겠습니다.


감사합니다.


안녕하세요.


지금까지 우리는 처음에 빈 슬라임 변수를 하나 두고 사용자가 어느 버튼을 누르냐에 따라 그 변수에 s1 또는 s2를 집어넣어서 처리를 했습니다.


그런데, battle 함수를 이용하면 빈 슬라임 변수 없이 처리가 가능합니다. 아래를 보시죠.




19행, 98행, 105행에서 빈 슬라임 변수를 모두 주석처리했습니다.


그리고 113행에서 배틀 함수에 슬라임 인수 s가 들어가도록 수정한뒤, 100행과 107행에서 배틀 함수의 인수로 s1 또는 s2를 넣어줬습니다.


이렇게 하면 왼쪽버튼을 클릭할때 s에 s1이 들어가고 오른쪽버튼을 클릭할때 s에 s2가 들어가는거죠.


머리를 쓰면 쓸수록 코드가 간결해지네요^^


감사합니다.

+ Recent posts