안녕하세요.


자바로 게임 만들기 - 슬라임 퇴치 게임 2탄을 시작해볼까합니다.


1탄은 TUI였지만 2탄은 GUI로 만들겠다고 했었죠. 이번시간에는 GUI의 기본 바탕이 되는 '윈도우'를 만들어볼까 합니다.


자바에서는 윈도우를 프레임(frame)이라고 부릅니다. 사전을 찾아보면 액자나 틀, 뼈대라고 나오는데 나름 납득이 가는 명칭입니다.



자, 그럼 스터디01에 적혀있는 기존의 코드를 싹 지우고 아래와 같이 새롭게 코딩을 해봅시다.



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
// Study01.java
 
package study;
 
import javax.swing.JFrame;
 
public class Study01 {
 
    public static void main(String[] args) {
 
        // 프레임 생성
        JFrame frm = new JFrame("슬라임 퇴치하기");
 
        // 프레임 크기 설정
        frm.setSize(350300);
 
        // 프레임을 화면 가운데에 배치
        frm.setLocationRelativeTo(null);
        
        // 프레임을 닫았을 때 메모리에서 제거되도록 설정
        frm.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
 
        // 프레임이 보이도록 설정
        frm.setVisible(true);
    }
 
}
 
cs


하나씩 설명 들어갑니다~


- 5행 : 임포트 문장은 수작업으로 적어줘도 되지만 다른 코드를 적고나서 컨트롤 + 시프트 + O 하면 자동 입력되죠^^


- 12행 : 이번 강좌의 핵심문장입니다. 기존에 자바에 내장돼있는 클래스인 JFrame 클래스를 이용해서 프레임을 만드는 문장입니다. 생성자의 인수가 프레임의 제목이 됩니다. (JFrame의 J는 자바의 이니셜이 아닐까 추측해봅니다)


- 15행 : setSize 함수는 가로값, 세로값을 인수로 받아서 프레임의 크기를 설정합니다.


- 18행 : 함수이름이 좀 어렵죠? '~에 관련하여 위치 설정'이라는 뜻인데 인수에다가 null을 집어넣으면 위치를 화면 가운데로 설정합니다.


- 21행 : 이 코드를 안적으면 X를 눌러서 창을 닫아도 프로그램이 종료가 안됩니다. 이클립스 콘솔창에 있는 빨간 네모를 눌러줘야 꺼집니다.


- 24행 : 필수 코드입니다. 안적으면 화면에 프레임이 나타나지 않습니다.



자, 이제 실행해봅시다.




성공이군요^^


다음 시간에는 이 프레임에다가 버튼을 추가해보도록 하겠습니다.

감사합니다.



안녕하세요.


이제 슬라임 퇴치 게임 완성을 위한 마지막 관문만 남았습니다.


슬라임이 모두 죽었을 때 '게임 클리어'를 표시하고 게임을 종료시키는거죠.



우선, 인간이 슬라임을 모두 퇴치할 수 있도록 인간의 공격력을 30으로 올려줍시다.




간단하죠?


이제 메인 클래스로 가서 게임 클리어를 코딩하겠습니다.




// Study01.java



슬라임이 '살아있을때만 공격' 코드 밑에 이처럼 코딩해주시면 되겠습니다.


자, 이제 완성입니다. 실행해봅시다.






잘되는군요^^ 그동안 수고하셨습니다^^ (아래는 코드 파일입니다)



Human.txt

Slime.txt

Study01.txt




그런데 이게 게임 완성이라니 너무 허접하다구요? ㅎ 맞습니다. 1번과 2번만 적어주면 주인공이 이겨버리는 극히 단순한 게임이죠. 게임 진행도 글자로만 진행이 되고... (이렇게 사용자와의 상호작용을 글자로 하는 방식을 TUI라고 합니다. Text User Interface의 약자죠)


하지만 자바를 전혀 모르던 상태에서 이 정도라도 뭔가 결과물을 만들었다는 사실이 뿌듯한 분도 계실듯 합니다. 게임을 만들면서 변수, 자료형, 함수, 클래스 등의 개념도 어느정도 잡히셨을 겁니다.


그래도 아쉬우시죠? 본 게시물의 제목을 보면 '1탄 완성'입니다. 이 말인 즉슨 2탄도 있다는 뜻이죠. ㅎㅎ


41강부터는 이 슬라임 게임을 GUI(Graphic User Interface의 약자)방식으로 바꿔볼까 합니다. 그래픽적인 게임으로 수정한다는 뜻입니다. 그리고 슬라임이 체력이 깎이면 자신이나 동료를 치료하기도 하고, 공격이 빗나가기도 하는 요소를 추가하여 좀 더 게임답게 만들어보겠습니다.


그럼 2탄을 기대해주세요.


감사합니다.


안녕하세요. 


저번 시간에 버그를 발견했었죠? 슬라임이 죽은뒤에도 주인공을 공격하는 문제가 있었습니다.


일단 이 버그를 잡아보겠습니다.


슬라임 클래스로 가주세요.




알고나니 간단하죠? 슬라임의 체력이 있을때만 어택함수가 동작하도록 수정했습니다.


자, 실행해봅시다.







사망 후에 주인공을 공격하는 증상은 사라졌습니다.


하지만 계속 1을 입력할 경우 죽은 슬라임을 확인사살하는 새로운 버그를 발견했네요.


슬라임이 죽었을때는 더이상 그 슬라임을 공격못하게 하고 싶은데... 어떻게 해야 될까요?


메인 클래스로 고고씽~





// Study01.java



49~59행을 봐주세요.


슬라임이 죽었으면 죽었다고 메세지 출력하고, 그 외의 경우에는 전투가 일어나도록 했습니다.


실행해봅시다.







죽은뒤에도 1을 누르면 죽어있다는 메세지가 뜸을 알 수 있습니다.


그리고 주인공이 죽으면 게임오버가 뜨는 것도 확인할 수 있습니다.


다음 시간에는 슬라임이 모두 죽으면 '게임 클리어'가 뜨도록 코딩을 해보겠습니다.


감사합니다.



안녕하세요.


이번 시간에는 슬라임이 죽었을때를 코딩해보겠습니다.


어느 클래스에다가 코딩해야될까요? 스터디01 클래스?(앞으로는 메인 클래스라고 하겠습니다) 슬라임 클래스? 휴먼 클래스?


정답은 휴먼 클래스입니다. 슬라임을 공격하는 코드가 있기 때문이죠.


아래처럼 하면 되겠습니다.



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
// Human.java
 
package study;
 
class Human {
 
    String name;
    int hp = 100;
 
    public Human(String n) {
        name = n;
    }
 
    public void attack(Slime s) {
 
        System.out.println("인간은 " + s.name + "를 공격했다");
        s.hp = s.hp - 10;
 
        if (s.hp < 1) {
            System.out.println(s.name + "는 사망했다\n");
        } else {
            System.out.println("현재 " + s.name + "의 체력은 " + s.hp + "이다\n");
        }
 
    }
 
}
 
cs

슬라임의 체력을 깎는 코드 다음에 위치하는게 적절해보입니다.

체력이 1보다 작으면 사망했다고 출력하고 그렇지 않으면 현재 슬라임의 체력을 출력합니다.

자, 실행해봅시다.





사망했다...까지는 잘 되는데 어라라?! 죽은 슬라삐가 알렉스를 공격하는군요. 좀비모드?!


메인함수에 있는 s.attack(h); 가 실행돼서 나타나는 현상입니다.


이래서는 안되겠죠. 다음 시간에는 요 버그를 잡아보도록 하겠습니다. (다음 강의를 보시기 전에 스스로 해결하면 더 좋겠죠^^)


감사합니다.


안녕하세요.


일단 메인함수의 if문을 한번 봐주세요.



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
            if (target == 1) {
 
                // 인간의 공격
                h.attack(s1);
 
                // 슬라임의 반격
                s1.attack(h);
 
            } else if (target == 2) {
 
                h.attack(s2);
                s2.attack(h);
 
            } else {
 
                JOptionPane.showMessageDialog(null"올바른 숫자를 입력하세요");
 
            }
cs


객체인수 기법을 사용하여 많이 간략해졌지만 슬라임의 개체수만큼 공격과 반격 구문을 적어줘야 된다는 단점이 남아있습니다. 게다가 슬라임의 체력이 소진됐을때도 추가해줘야되니 우선적으로 리팩토링이 더 필요해보입니다.


이번에 소개해드릴 기법은 '빈 슬라임 변수'를 사용하는 건데요, 우선 스터디02에다가 아래와 같이 코딩해봅시다.



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// Study02.java
 
package study;
 
public class Study02 {
 
    public static void main(String[] args) {
 
        // 빈 슬라임 변수
        Slime s = null;
 
        // 슬라임 객체 생성
        Slime s1 = new Slime("슬라삐");
        Slime s2 = new Slime("슬라디");
 
        s = s1;
 
        System.out.println(s.name);
 
    }
 
}
 
cs


10행을 보시면 슬라임을 담을 수 있는 박스를 준비해놓는 내용이네요. null을 넣었다는 말은 아무것도 들어있지 않다는 뜻이겠죠.


13, 14행에서 슬라임 객체들이 박스에 들어갔고... 16행이 이번 강좌의 하이라이트네요. s1이 s에 들어갑니다. 이렇게 되면 s1이나 s나 동일해지는거죠.


18행에서 s.name하면 슬라삐가 출력이 되겠습니다.





자, 이제 이 기법을 메인함수에 적용해봅시다.



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
// Study01.java
 
package study;
 
import javax.swing.JOptionPane;
 
public class Study01 {
 
    public static void main(String[] args) {
 
        // 빈 슬라임 변수
        Slime s = null;
 
        // 슬라임과 인간 객체 생성
        Slime s1 = new Slime("슬라삐");
        Slime s2 = new Slime("슬라디");
        Human h = new Human("알렉스");
 
        System.out.println(s1.name + "와 " + s2.name + "가 나타났다! 당신의 이름은 " + h.name + "이다\n");
 
        while (true) {
 
            // 인풋박스
            String sTarget = JOptionPane.showInputDialog("어느 슬라임을 공격하겠습니까? 1은 " + s1.name + " 2는 " + s2.name);
 
            // 널값이나 빈값이 입력되면 종료
            if (sTarget == null || sTarget.equals("")) {
                System.exit(0);
            }
 
            // 형변환
            int target = Integer.parseInt(sTarget);
 
            if (target == 1) {
                
                s = s1;
 
            } else if (target == 2) {
                
                s = s2;
                
            } else {
 
                System.out.println("올바른 숫자를 입력하세요");
 
            }
 
            h.attack(s);
            s.attack(h);
 
        } // while 끝
    }
 
}
cs


형변환 다음에 나오는 if문의 역할이 단순해졌습니다. 1이면 s에다가 s1을 집어넣고, 2면 s에다가 s2를 집어넣는거죠. 실질적인 행동은 if문 밖에다가 한번씩만 적어주면 되겠습니다.



다음시간에는 드디어 슬라임의 체력이 소진됐을때를 코딩할수 있겠죠? ㅎ


감사합니다.


안녕하세요.


지난시간에 에러의 원인을 알았으니 이번시간에는 에러를 잡아보도록 하죠.






1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// Study01.java
 
package study;
 
import javax.swing.JOptionPane;
 
public class Study01 {
 
    public static void main(String[] args) {
 
        // 슬라임과 인간 객체 생성
        Slime s1 = new Slime("슬라삐");
        Slime s2 = new Slime("슬라디");
        Human h = new Human("알렉스");
 
        System.out.println(s1.name + "와 " + s2.name + "가 나타났다! 당신의 이름은 " + h.name + "이다\n");
 
        while (true) {
 
            // 인풋박스
            String sTarget = JOptionPane.showInputDialog("어느 슬라임을 공격하겠습니까? 1은 " + s1.name + " 2는 " + s2.name);
            
            // 형변환
            int target = Integer.parseInt(sTarget);
cs


일단 코드 앞부분만 가져왔습니다.


에러가 나는 원인은 sTarget 변수에 null값이 들어가거나 빈값이 들어갈 경우 형변환이 불가능하기때문이었죠.


그렇다면 답은 간단합니다. 인풋박스와 형변환 사이에다가 아래와 같은 구문을 넣으면 되겠죠.



만약 sTarget 변수에 null값이 들어가거나 빈값이 들어갈 경우 게임을 종료하라.





정답을 알아보기 전에 일단 한가지 알아두셔야할 게 있는데요, 아래 예제를 보시죠. (스터디02에서 실습하세요)



변수값이 서로 같은지 비교할때 ==을 사용했습니다. 그런데 이건 숫자끼리 비교할때이구요. 문자끼리 비교할때는 아래와 같이 해야 합니다.







문자끼리 비교할때도 == 이 방식이 먹힐때가 있지만 안먹힐때도 있습니다. 그래서 문자끼리 비교할때는 무조건 아래와 같은 방법을 쓰시는 게 좋습니다.



변수1.equals(변수2)



자, 이제 정답을 봅시다.





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
// Study01.java
 
package study;
 
import javax.swing.JOptionPane;
 
public class Study01 {
 
    public static void main(String[] args) {
 
        // 슬라임과 인간 객체 생성
        Slime s1 = new Slime("슬라삐");
        Slime s2 = new Slime("슬라디");
        Human h = new Human("알렉스");
 
        System.out.println(s1.name + "와 " + s2.name + "가 나타났다! 당신의 이름은 " + h.name + "이다\n");
 
        while (true) {
 
            // 인풋박스
            String sTarget = JOptionPane.showInputDialog("어느 슬라임을 공격하겠습니까? 1은 " + s1.name + " 2는 " + s2.name);
            
            // 널값이나 빈값이 입력되면 종료
            if(sTarget == null || sTarget.equals("")) {
                System.exit(0);
            }
            
            // 형변환
            int target = Integer.parseInt(sTarget);
 
            if (target == 1) {
 
                // 인간의 공격
                h.attack(s1);
 
                // 슬라임의 반격
                s1.attack(h);
 
            } else if (target == 2) {
 
                h.attack(s2);
                s2.attack(h);
 
            } else {
 
                JOptionPane.showMessageDialog(null"올바른 숫자를 입력하세요");
 
            }
 
        } // while 끝
    }
 
}
 
cs


23~26행이 추가해준 부분입니다. 널값은 ==를 이용해 비교했고, 빈값은 방금 배운 equals함수를 이용해서 비교했습니다. (널값은 equals함수가 통하지 않기 때문에 ==로 비교해주시면 됩니다.)





다음 시간에는 슬라임의 체력이 소진됐을때를 코딩해보겠습니다.


감사합니다.


안녕하세요.


게임 도중에 인풋박스를 취소하거나, 아무것도 안적고 확인을 누르면 아래와 같은 에러가 뜨는데 해결책을 찾아보도록 합시다. (엄밀히 말하면 두 경우 에러메세지 내용이 조금 다르지만 대표로 한 이미지만 올려둡니다)










에러가 나는 이유를 분석하기 전에, 일단 코드를 아래와 같이 수정해주세요.



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
// Study01.java
 
package study;
 
import javax.swing.JOptionPane;
 
public class Study01 {
 
    public static void main(String[] args) {
 
        // 슬라임과 인간 객체 생성
        Slime s1 = new Slime("슬라삐");
        Slime s2 = new Slime("슬라디");
        Human h = new Human("알렉스");
 
        System.out.println(s1.name + "와 " + s2.name + "가 나타났다! 당신의 이름은 " + h.name + "이다\n");
 
        while (true) {
 
            // 인풋박스
            String sTarget = JOptionPane.showInputDialog("어느 슬라임을 공격하겠습니까? 1은 " + s1.name + " 2는 " + s2.name);
            
            int target = Integer.parseInt(sTarget);
 
            if (target == 1) {
 
                // 인간의 공격
                h.attack(s1);
 
                // 슬라임의 반격
                s1.attack(h);
 
            } else if (target == 2) {
 
                h.attack(s2);
                s2.attack(h);
 
            } else {
 
                JOptionPane.showMessageDialog(null"올바른 숫자를 입력하세요");
 
            }
 
        } // while 끝
    }
 
}
 
cs


21~23행을 잘보세요. 기존에는 인풋박스 내용을 형변환해서 변수에 집어넣은 것까지 한줄로 처리했습니다만, 일단 스트링 변수에 넣고 형변환하는 식으로 두줄로 쪼개놨습니다. (다른 부분은 건드리지 않았습니다)


이 상태에서 실행을 하고 취소버튼을 눌러보시기 바랍니다.






맨처음 에러가 유발된 부분이 맨밑에 적혀있습니다. 23행에서 에러가 시작됐다고 돼있네요. 23행은 형변환하는 코드가 있는 부분이네요.


에러가 왜 나는지 짐작이 가시나요?


인풋박스를 취소를 하게 되면 sTarget 변수에 아무런 값도 들어가지 않습니다. 이걸 null(널) 상태 또는 null값이 들어갔다고 표현합니다. (에러메세지 맨 윗줄의 맨 오른쪽을 보시면 null이라고 적혀있죠?) 아무런 값이 없으니 형변환이 불가능한게 당연한거죠.


이번에는 인풋박스에 아무것도 안적고 확인을 눌러봅시다.








이번에도 형변환하다가 에러가 났네요. null이 적혀있던 자리에 "" 이게 적혀있네요. 따옴표속에 아무것도 안적혀있다는, 다시말해 빈값이 입력됐다는 것이죠. 빈값이 형변환 안되는 것도 당연한 사실입니다.





갑자기 혼란스러우신가요? 변수에 아무런 값도 안들어간거랑 빈값이 들어간거랑 도대체 무슨 차이냐고 반문하시는 분이 계실듯 합니다. 비유를 하자면 전자렌지에 아무것도 안넣은 거랑 빈접시를 넣은 것의 차이랄까요? 아무튼 두 경우 다 그 상태에서 전자렌지를 작동시키는 행동은 에러겠죠.


이렇게해서 에러가 나는 원인은 찾았습니다. 다음 시간에는 에러 해결을 해보도록 하겠습니다.


감사합니다.


안녕하세요.


일단 휴먼 클래스 코드를 보시죠.






1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// Human.java
 
package study;
 
class Human {
 
    String name;
    int hp = 100;
 
    public Human(String n) {
        name = n;
    }
 
    public void attack(Slime s) {
 
        System.out.println("인간은 " + s.name + "를 공격했다");
        s.hp = s.hp - 10;
        System.out.println("현재 " + s.name + "의 체력은 " + s.hp + "이다\n");
        
    }
 
}
 
cs

17행과 18행을 추가해줬습니다.

기존의 방식대로 했다면 이 두행이 슬라임의 객체수만큼 메인함수에 적혀있어서 코드가 복잡해 보였지만 객체인수 기법을 사용하여 휴먼 클래스에 한번만 적어주면 어떤 슬라임을 공격하든 대응이 가능해졌습니다.

이제 슬라임 클래스도 한번 보시죠.




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
// Slime.java
 
package study;
 
import javax.swing.JOptionPane;
 
class Slime {
 
    String name;
    int hp = 80;
 
    // 생성자
    public Slime(String n) {
 
        name = n;
 
    }
 
    // 공격
    public void attack(Human h) {
 
        System.out.println(name + "는 " + h.name + "을 공격했다");
        h.hp = h.hp - 10;
 
        if (h.hp < 1) {
            JOptionPane.showMessageDialog(null"Game Over");
            System.exit(0);
        }
 
        System.out.println("현재 " + h.name + "의 체력은 " + h.hp + "이다\n");
 
    }
 
}
 
cs


이런식으로 메인함수에 써줬던 내용을 넣어줄 수 있습니다.


27행의 함수는 프로그램을 끝내는 함수입니다. 통으로 외우시면 되겠습니다.


마지막으로 스터디01로 가봅시다.





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
// Study01.java
 
package study;
 
import javax.swing.JOptionPane;
 
public class Study01 {
 
    public static void main(String[] args) {
 
        // 슬라임과 인간 객체 생성
        Slime s1 = new Slime("슬라삐");
        Slime s2 = new Slime("슬라디");
        Human h = new Human("알렉스");
 
        System.out.println(s1.name + "와 " + s2.name + "이 나타났다! 당신의 이름은 " + h.name + "이다\n");
 
        while (true) {
 
            // 인풋박스
            int target = Integer
                    .parseInt(JOptionPane.showInputDialog("어느 슬라임을 공격하겠습니까? 1은 " + s1.name + " 2는 " + s2.name));
 
            if (target == 1) {
 
                // 인간의 공격
                h.attack(s1);
                
                // 슬라임의 반격
                s1.attack(h);
 
            } else if (target == 2) {
 
                h.attack(s2);
                s2.attack(h);
 
            } else {
                
                JOptionPane.showMessageDialog(null"올바른 숫자를 입력하세요");
                
            }
 
        } // while 끝
    }
 
}
 
cs


어떤가요? 코드가 상당히 간결해지고 이해하기 쉬워졌죠? (두번째 슬라임의 이름을 바꿨습니다)


만약에 어택함수의 자세한 내용이 궁금해지면 attack에다가 마우스 포인터를 갖다대고 컨트롤을 누른 상태에서 클릭하면 어택함수가 정의된 곳으로 순간이동합니다^^





그런데말입니다. 인풋박스를 취소할때마다 뜨는 에러 어떻게 안될까요? 일일이 정지버튼을 누르기도 번거럽죠? 다음 시간에는 이 점을 해결해보도록 하겠습니다.


감사합니다.

+ Recent posts