[코드스쿼드 코코아_개인 프로젝트] GUI 코인 먹기 게임 (1)

Kyu·2020년 12월 1일
0
post-thumbnail

코인 먹기 게임

https://github.com/kyu-kim-kr/cocoa-personal-project

게임 목표

  1. 상, 하, 좌, 우, 대각선으로 움직이는 플레이어
  2. 맵에서 랜덤으로 코인을 생성
  3. 코인을 먹으면 점수가 올라감
  4. 일정 점수가 되면 게임이 끝남

시작

  1. 뭐부터 시작해야할지 모르겠음
  2. gui 관련 아무 게임이나 따라하면서 뭘 만들어야할지 감각을 익히는중
  3. 그래도 여전히 무슨 코드를 작성해야할지 모르겠음
  4. 실제로 내가 구현하고 싶은 움직이는 플레이어를 그대로 따라 배우는중
  5. 그걸보면서 모르는 개념을 공부중..이중버퍼같은...

Commit history

1. Structure

처음에 시작할 때 구조화부터 했다. 메인메소드와 프레임과 패널 그리고 쓰레드까지 나누었다. 프레임과 패널 따로 두어야 보기 편할것 같았고 쓰레드도 추가했다.

2. Set basic frame

프레임에 기본적으로 저장해야하는 setTitle이나 setBounds 값들을 적고 커밋했다.

3. Add panel and set it to BorderLayout.CENTER

프레임에 페널을 BorderLayout형태로 넣었다. 처음에 페널에다가 여러 컴포넌트를 넣어서 자동으로 배열시키려고 그렇게 했던거 같다.

4. Add KeyListener to move character

키보드 입력에 따라 플레이어를 움직이도록 할거기때문에 KeyListener을 추가했다. 인터페이스를 구현하지않고 직접 추가했다.

5. Change minor things about frame

프레임에 관련된 코드를 변경했다. setBounds는 setSize로 바꾸고 화면을 중앙에 배치하는 코드 등 작은 부분들 변경했다.

6. Delete everything and re-start

내가 원하는건 플레이어 한명이 있고 코인이 한개 있는 그런 화면이었다. 굳이 여러 클래스로 나눌 필요도 없을거 같았고 지금에서야 알았지만 BorderLayout형식으로 지정해줄 필요도 없었고 여러가지 불필요한게 많아 다시 시작해야겠다고 생각했다.

7. Draw player's image

툴킷을 이용해서 플레이어 이미지를 불러왔다. 사실 아직도 툴킷의 용도를 정확히 모르겠다. 이름으로 추측하기로는 여러가지 것들을 사용할 수 있는 것으로 보이지만 javadoc을 봐도 와닿지가 않는다.

여기서 paint()와 update()가 어떻게 작동하는지 많이 찾아보고 이해하려고 노력했다. repaint()없이 자동으로 몇몇 상황에서 paint()가 불러와지는 건 알겠다. 책에는 paint()나 upate()가 호출된다고 했는데 무슨 말인지 모르겠다. 여러 블로그를 봤을 때 추측하기론 update()가 화면을 지우고, paint()가 화면을 그리는 것 같다.

그리고 repaint()를 호출하면 update(g)가 호출되고 paint(g)가 호출된다는데 이 과정이 이해가 되지 않는다.

8. Add keyPressed

실제로 키가 입력되었을 때 발생되어야할 코드들을 작성했다.

9. Create xPlayer and yPlayer to move imagePlayer.

먼저, 변수의 이름을 왜 이렇게 지었는지 설명하고 싶다. xPlayer, yPlayer 뿐만아니라 이후에 widthPlayer라던가 heightCoin이라던가 이렇게 지었는데 이렇게 지어도 괜찮은지 잘 모르겠지만, 중복되것 같은 거나 중요한 단어를 먼저 언급하고 그 뒤에 중요한 단어를 받는 객체가 나오도록 했다. 내게는 playerX나 playerWidth보다 가독성이 더 낫다고 생각했다. 음, 왜이렇게 지었는지 설명하고 싶었으나 설명을 못하겠다. 그냥 느낌상 더 가독성이 좋게 느껴졌다.

그리고 이미지의 움직임을 주기위해서 키리스너에 좌표 값에 +-5 값을 주었는데, 다른 코드를 보면서 키를 눌렀을때 좌표값을 주는거는 다른 메소드에 넣는게 좋다고 느껴져서 그렇게 했다. 이후에 다른 블로그에서 보았는데 만약에 같이 넣으면 대각선 키가 안먹는다고 설명했던 것을 봤다.

게임에서 중요한 개념인 더블 버퍼개념도 이 과정을 구현하면서 공부를 많이 했다. 그냥 하면에다가 넣고 싶은것을 차례대로 그리면 그 과정이 화면에서 다 나오기 때문에 화면이 깜박거리는 거처럼 보인다. 이것을 해결할 수 있는게 더블 버퍼개념이다. 더블버퍼는 가상의 공간에 모든 것을 그려주고, 완성된 그림을 화면에 출력해주는 방식이다.

다음과 같이 코드를 작성하면 된다.

 public void paint(Graphics g) {
        //가상에 그려준다
        bufferImage = createImage(FRAME_WIDTH, FRAME_HEIGHT);
        gp = bufferImage.getGraphics();
        gp.drawImage(imagePlayer, xPlayer, yPlayer, this);

        //가상에 그린 것을 화면에 출력
        g.drawImage(bufferImage, 0, 0, this);
    }

10. Create Thread to keep checking if an isKey in move() is true

클래스 자체에 쓰레드로 사용하기 위해 Runnable를 구현했다. while(true)문에 좌표를 찍어주는 메소드와 repaint()를 넣었다. 그럼 계속 입력값이 있는지 KeyLister을 통해 체크하고 입력값이 있으면 키 입력값과 관련된 boolean 값들이 true로 바뀌면서 좌표를 찍어주는 move()에서 조건문이 true로 바뀌면서 좌표가 바뀐다.

11. Better moves for some reason

paint()에 update(g)를 주고 update()에 g.drawImage() 코드를 넣는다. 앞서 언급했듯이 아직 paint와 update간에 상관관계를 잘 몰라서 이해는 못하겠는데 블로그에서 참고해서 넣었다. 느낌상 더 부드럽게 움직이는 거 같은건 착각이려나?

12. Print counting repaint() at left-top corner

repaint()를 몇번했는지 참고삼아 보려고 코드를 적었다. 이런 간단한 게임인데 cpu가 너무 많이 돌아가는거 아닌가 생각이 든다.

13. Add imageCoin in Frame

플레이어를 움직이도록 했으니 이제 코인을 화면에 넣는다.

14. Add a method crashPlayerNCoin

랜덤클래스로 코인을 화면에 랜덤으로 뿌려준다. y좌표에서 상수 30에 관한 것은 프레임 창의 상태창도 좌표에 포함되기 때문에 그 상태창의 좌표값을 없애기 위한 것이다. 다른 블로그를 참고해서 부딪치는 로직을 만들었다. 이해하는 데 좀 오래걸렸다.

15. Fixed image getWidth and getHeight returning -1 inappropriately

앞에서 블로그를 참고해서 잘 구현했는데 동작하지 않는 문제가 발생했다. 디버거를 통해서 이미지의 폭넓이 값을 얻는 코드에서 모든 플레이어와 코인에 대한 이미지의 폭넓이 값이 -1로 리턴되어서 검색을 통해 해결했다. 이유는 잘 모르겠지만 툴킷을 지우고 대신에 Image자체에서 ImageIcon 을 통해서 값을 불러오면 정상 작동한다.


정리

사실 이 모든 과정들이 내 수준에서 4~5일 정도 걸릴거라 예상했는데 예상보다 빨리 끝나서 남은 이틀은 자바의정석 예제를 참고해서 장애물들을 만들어보려한다.

2편 : https://velog.io/@kyukim/%EC%BD%94%EB%93%9C%EC%8A%A4%EC%BF%BC%EB%93%9C-%EC%BD%94%EC%BD%94%EC%95%84%EA%B0%9C%EC%9D%B8-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-GUI-%EC%BD%94%EC%9D%B8-%EB%A8%B9%EA%B8%B0-%EA%B2%8C%EC%9E%84-2

profile
TIL 남기는 공간입니다

0개의 댓글