adsense



요시카 스크램블 - 보스 캐릭터를 바꿔보자

JAVA 2D 슈팅게임 소스 - 요시카 스크램블


답변으로 적다 보니 길어져서 그냥 이참에 포스팅 하나 쓰기로 했습니다...

새로운 보스가 등장했다!!
YScramble_20141007.zip

※스크린 샷에 사용된 그림은 Galette에 저작권이 있는 상용게임의 그림으로 어디까지나 참고사용이므로 스크린샷에만 보여드리고 프로젝트 안에는 포함하지 않았습니다.

※첨부된 파일의 프로젝트는 보스 캐릭터의 이미지를 바꾸는 코드(방법 2)가 포함되어 있습니다만, 보스 그림이 rsc 폴더에 없습니다. boss1.png, boss2.png.. 와 같은 식의 이름으로 된 보스 그림 파일을 rsc/game 폴더에 추가해 주셔야 합니다.

※가급적이면 이 프로젝트를 그대로 쓰지 말고, 포스트를 참조해 201310 프로젝트를 사용해서 직접 수정해 보시기 바랍니다.


보스 이미지를 레벨마다 바꾸는 방법은

1. 보스로 쓸 그림을 미리 읽어서 메모리에 올려두기
2. 그때 그때 보스 그림을 새로 읽어오기
두 가지 방법이 있는데,

우선 1.의 방법을 알아보겠습니다.

Image enemy[]=new Image[5];//적 캐릭터
이 밑에
Image bossImage[]=new Image[(원하는 보스의 수)];//적 보스
이렇게 한 줄 추가해주고

gamescreen.enemy[1]=makeImage("./rsc/game/enemy1.png");//보스 추가
이 부분을 찾아서 이건 주석처리하고 그 밑에

for(i=0;i<gamescreen.bossimage.length;i++)
 gamescreen.bossImage[i]=makeImage("./rsc/game/boss"+ i +".png");//보스 추가
이렇게 추가합니다.

이때 보스의 그림 파일 이름은
boss0.png
boss1.png
boss2.png
.
.
이런 식이 되니까 적당히 파일 이름을 맞춰주면 되겠습니다.

그리고 public void Draw_ENEMY() 에서 drawImageAnc(enemy[1], buff.dis.x, buff.dis.y, 4);//보스 출력
를 찾아서

drawImageAnc(bossImage[main.level], buff.dis.x, buff.dis.y, 4);//보스 출력

이렇게 수정하면 됩니다.

만약 보스의 크기가 많이 다르다면
Enemy클래스의 case 1://보스 전용 셋팅
부분에서 타격영역에 해당하는 hitrange 값을 적당히 수정해서 맞춰줍니다.

여기서 좀 더 발전시킨다면, 내구력이나 공격 방식, 움직임 등도 main.level에 따라 수치를 이것 저것 조절해 가면서 레벨 별로 개성적인 보스가 나타나게 할 수도 있습니다.


그리고 2의 방법을 알아보자면

gamescreen.enemy[1]=makeImage("./rsc/game/enemy1.png");//보스 추가

gamescreen.enemy[1]=makeImage("./rsc/game/boss0.png");//보스 추가
식으로 우선 최초로 등장할 보스 이미지로 변경해주고,

public void process_BULLET() 함수에서
if(ebuff.life--<=0){//적 라이프 감소
if(ebuff.kind==1){
if(gamecnt<2100) gamecnt=2100;
}
부분을 찾습니다. 적이 라이프가 감소되어 파괴되는 부분인데요,
이 바로 밑에
if(ebuff.kind==1)//보스라면
gamescreen.enemy[1]=makeImage("./rsc/game/boss"+ level +".png");//보스 추가
와 같이 새 보스 그림을 읽어들이게 합니다.
환경에 따라서 이때 다소의 렉이 발생할 수도 있습니다.

그리고 한 군데 더, 보스를 처치하지 못하고 타임아웃으로 도망가게 했을 때
if(gamecnt>2210){// 보스전 타임 아웃으로 보스전을 종료한다
gamescreen.boss=false;
gamecnt=0;
System.out.println("보스 타임아웃");
}
이 부분에서도
gamescreen.enemy[1]=makeImage("./rsc/game/boss"+ level +".png");//보스 추가
이것을 삽입해 줍니다.

보스 출력 부분은 따로 수정하지 않아도 되고,
그림 파일 이름 규칙과 타격판정 영역은 1과 같은 방식으로 수정합니다.



글이 길어져서 그렇지, 사실 별 어려운 내용은 없습니다.. 그냥 이미지를 추가하고, 상황에 따라 해당하는 이미지를 출력하게 하는 것 뿐.

마지막으로, 만약 보스를 5개 정도 준비했는데, 5회 이상 보스를 만나게 됐다면? 마지막 보스만 계속 나오게 할 것인가, 첫째 보스부터 다시 루프를 돌 것인가, 엔딩같은 걸 나오게 할 것인가.. 요건 여기서는 생략하겠습니다.



덧글

  • 2014/11/05 14:44 # 삭제 답글 비공개

    비공개 덧글입니다.
  • 펭귄대왕 2014/11/06 03:06 #

    비트맵 이미지를 출력하는게 목적이라면 이 포스팅에 첨부된 프로젝트를 받아 소스를 보시면 makeImage라는 함수로 png파일을 Image 객체로 사용하고 있습니다.

    단지 만드신 소스는 버퍼로 Image가 아니라 BufferedImage를 쓰고 있으니, makeImage를 조금(?) 고쳐서
    public BufferedImage makeImageB(String furl){
    BufferedImage img = null;
    try{
    File file = new File(furl);
    img = ImageIO.read(file);
    }catch(Exception e){
    e.printStackTrace();
    }

    return img;
    }
    이런 식으로 하면 됩니다.
    사용하는 파일은 png 파일로, 24비트 png로 투명을 줘서 만들어두면 별도의 투명 처리 필요없이 알아서 출력해줍니다.

    그런데, Canvas 안쓰고 JFrame에서 직접 그래픽 객체 받아가지고 갱신하는건 속도가 꽤 느려서 게임 화면 갱신방법으로는 좋지 않을 것 같습니다.
  • 2014/11/08 23:59 # 삭제 답글 비공개

    비공개 덧글입니다.
  • 펭귄대왕 2014/11/09 01:07 #

    메일 드렸습니다
  • 2014/11/09 23:55 # 삭제 답글 비공개

    비공개 덧글입니다.
  • 펭귄대왕 2014/11/10 00:39 #

    제가 도와드릴 수 있는거라면요. 간단한 내용은 블로그에 리플로 달아주시고, 긴 내용이라면 valpa@네이버 로 메일 주시면 됩니다.
  • 2014/11/11 09:52 # 삭제 답글 비공개

    비공개 덧글입니다.
  • 2014/11/13 15:07 # 삭제 답글 비공개

    비공개 덧글입니다.
  • 펭귄대왕 2014/11/13 15:34 #

    이클립스에서 Show View-Console을 활성화하면 오류가 나는 위치와 어떤 오류가 나는지 확인할 수 있습니다.
    그쪽을 참조해보시고 오류의 원인을 알 수 없다면 어떤 오류가 나는지 알려주세요.
  • 2014/11/13 22:45 # 삭제 답글 비공개

    비공개 덧글입니다.
  • 펭귄대왕 2014/11/14 05:49 #

    숫자 이미지가 불러져있지 않은가봅니다. 디버깅 요령을 정리해봤으니 참고해보시면 좋겠습니다.
  • 2014/11/19 00:25 # 삭제 답글 비공개

    비공개 덧글입니다.
  • 펭귄대왕 2014/11/19 03:17 #

    XNA와 C#은 써 본 적 없지만.. 일단 이 두가지에 대해서 저보다 잘 아실 것 같으니 제 소스에 관한 것만.

    대충 게임엔진이란 건 매 프레임마다 새로 화면을 그리기 위한 순환구조,
    사용자 입력-키보드, 마우스, 터치스크린, 컨트롤러 등-을 받아들이기 위한 이벤트 콜백or리스너or인터페이스(오버라이드 함수)
    일단 이 두 가지는 반드시 있습니다.

    이 포스트에서 소개하는 프로젝트는 엔진을 쓰지 않았기 때문에 그런 순환구조까지 처음부터 만들어 쓰고 있는 거고요.
    (run() 함수 영역이 순환구조에 해당합니다)

    XNA를 대충 찾아보니
    LoadContent <- 여기서 이미지를 읽어들이고 있네요.
    Draw <- 이게 기본적인 그리기의 순환구조 역할을 하나 보네요.
    Update <- 그리고 이게 연산계열의 처리(좌표의 이동, 상태 변화, 각종 비교, 객체의 생성/소멸) 순환 구조를 담당하는 모양이고요.

    이거랑 제 소스를 대응시켜보면
    LoadContent는 Init_TITLE(), Init_GAME()이 해당하겠고,
    Draw는 dblpaint()가,
    Update는 process()와 keyprocess()가 각각 해당하겠습니다.

    XNA는 외부 입력이 따로 이벤트로 전달되는게 아니고 state를 읽어서 처리하는 모양이네요.
    이 경우는
    keyPressed는 KeyBoardState.GetState().isKeyDown으로 대응하고,
    keyReleased는 KeyBoardState.GetState().isKeyUp으로 대응하는 식으로 바꿔주는 방법도 있고,
    아니면
    keyprocess() 안에서 직접 키보드 스테이트를 읽어서 처리하는 방법, 그러니까
    switch(keybuff){
    .
    .
    .
    case FIRE_PRESSED:
    mydegree=-1;
    myimg=6;
    break;
    이런 걸
    if(키보드스테이트==스페이스키 눌려있음){
    mydegree=-1;
    myimg=6;
    }
    이런 식으로 대응해주면 될 듯 합니다.


    C#쪽에서 클래스/객체와 Vector같은 가변배열 처리가 어떻게 되는지 모르겠는데, 그거 말고 기본적인 처리는 위와 같이 맞춰보면 됩니다.

    단, 이건 awt자바라서 프레임 생성하는 클래스, 실제 화면을 그리는 클래스가 각각 따로따로 있어 그거 사이를 오가는게 좀 복잡해 보일 뿐입니다.
    C#이라면 그냥 전역으로 다 때려넣고 (Init_TITLE(), Init_GAME()도 하나로 합치고) 만들면 될 거 같네요.

    화면 그리기 부분같은 경우는, 아마 SpriteBatch를 생성해서 batch.Draw 이런 식인 모양인데..

    이 소스에서 보면 gc.drawImage가 거기에 해당합니다. 단, 인수는 각자 전용의 문법이 있고 환경에 따라 추가해야 할 인수, 필요없는 인수가 있으니 그것만 잘 맞춰주면 됩니다. 자바쪽이 그리기 기능이 특별한게 없어서 기본적인 Draw에만 맞춰도 되겠네요.

    예를 들어
    gc.drawImage(JavaImage, x, y, this);
    이런 형태는
    batch.Draw(Texture2DImage, Vector2(x,y));
    이 정도로 옮길 수 있겠습니다.

    코드가 자잘자잘하게 많아서 그렇지 큰 흐름으로 따라가 보면 별 대단한 건 없습니다. 단지 그만큼 각 코드가 무슨 역할을하는건지 이해가 좀 필요하겠습니다만..

    추가로 참고삼아
    http://icegeo.egloos.com/300704
    여기 소스랑 설명 보시면 아주 쪼끔 더 깔끔하게 정리돼 있습니다.

    차근차근, 배경 그리기-플레이어 캐릭터 올리기-플레이어 캐릭터 이동하기-총알 발사하기-적 등장시키기-총알과 적의 충돌-적과 플레이어의 충돌... 이런 식으로 단계별로 '소스를 참고해서 구현'한다는 느낌으로 하시는게 쉬울것 같습니다.
  • 대학생 2014/11/19 15:00 # 삭제

    좋은답변감사합니다 ^^!
  • 펭귄대왕 2014/11/19 18:12 #

    한 가지 추가로 더 고려하실 건, 자바의 그리기는 좌표계에 int를 쓰기 때문에 삼각함수를 사용하는 거리, 각도 계산식에서 제대로 된 값이 들어오지 않습니다.

    그때문에 좌표값들을 기본적으로 *100 해서 처리하고, 그릴때는 /100한 위치에 그려주고 있어서 연산이 좀 조잡해졌습니다.
    혹 좌표 숫자가 이상하다고 느끼셨다면 그런 이유입니다.
  • 밤콩 2015/11/14 01:22 # 삭제 답글

    안녕하세요 ! 펭귄대왕님
    윗 댓글들을 찬찬히 살펴보며 수정할것을 수정하고 도움받으며 보고있다 막히는부분이 발생하여 이렇게 댓글을남겨봅니다..
    현재 게임진행방식이 좌 우 인데
    응용하여 상하로 진행되게 바꾸고싶은데 캐릭터의 총알발사는 윗방향으로 향하게 수정이 되었는것같은데
    몬스터부분 및 몬스터 총알 배경의 진행방향 조절이 힘드네요.
    도움을주시면 감사하겠습니다..
  • 펭귄대왕 2015/11/14 10:05 #

    적 캐릭터 같은 경우
    class Enemy의 move 함수에서 //이동 처리 라고 된 부분을 보시면
    pos.x, pos.y를 직접 증감해서 적 캐릭터를 이동하고 있습니다.
    이때 값은 이동할 도트 수 *100이므로 pos.x-=500; 이라고 하면 오른쪽으로 5도트 이동하는 식입니다.
    세로 방향으로 한다면 주로 위에서 아래로 내려오므로 pos.y 값을 증가시켜주는 식으로 만들면 됩니다.

    총알은 조금 다른 방식으로 이동하는데,
    총알의 생성자(Bullet)을 보면 degree로 0~360도 (수직 위 방향이 0 입니다) 방향을 지정하고, speed로 이동 값을 지정하는 방식입니다.
    그러므로 총알을 발생시킬 때 degree를 180으로 지정하면 수직 아래로 총알이 진행하게 됩니다.
    적절한 값을 넣어보면서 총알의 비행 각도를 지정하게 해 주면 됩니다.

    배경화면도 마찬가지로 y좌표를 이동시켜주고, 화면 바깥으로 나갔는지의 판단, 나갔을 때 자리를 되돌려주는 것도 y좌표 중심으로 보면 됩니다.(이건 위치즈 플라이트 제작 강좌를 참조해도 좋습니다)

    총알과 적 캐릭터가 다양한 방향으로 이동하는 경우는 http://icegeo.egloos.com/300704 이쪽 게임에서 많이 사용하고 있으니 참조할만 합니다.
  • 밤콩 2015/11/14 14:51 # 삭제

    친절한 답변 감사합니다 !
  • 밤콩 2015/11/14 15:35 # 삭제

    펭귄대왕님 죄송한데 질문하나만 더드려보겠습니다..
    게임을 1:1 네트워크 플레이가 가능하게 바꾸고싶은데 각플레이하는 캐릭터 및 총알 좌표값만 전송한다치면
    적패턴및 공격하는 총알이 랜덤하게 바뀌는데 고정하는방법이 있을까요?
    그리고 다른 네트워크로 바꾸게되면 바꿔야하는부분이 어느부분이 있을까요

    정말 죄송하지만 이질문외에 이메일로 질문하나만 더하였습니다..
    혹시 아신다면 방법좀 올려주실수있을까 해서 남겨봅니다.
    자꾸 질문해서 죄송합니다
  • 펭귄대왕 2015/11/15 05:58 #

    메일로 답변..이라기보단 의견 드렸습니다. 정확한 답변은 아닐거같아 도움이 될지 모르겠습니다..
  • 밤콩 2015/11/15 06:43 # 삭제

    감사합니다 답장 바로확인하였습니다.
    정말 귀하신 시간 내주셔서 감사합니다.
    Slick은 어쩔수없이 포기해야될것같군요( 오류난부분은 라이브러리쪽이미지같은데..역시나 전잘모르겠습니다.)
    글을 읽고나니 제가 기존Slick으로 했을때보다 더 신경을 많이써야되는 부분이 많더라고요. 역시 다르십니다.
    클라1-서버클라2식 서버중개식으로 진행하였었고 호스트-게스트를 둔형식으로 바꾸고 만든다는생각하니 훨씬더 복잡하네요..
    몇일째 밤새며 아직 실력이많이 부족한학생인지라 이것저것해보는데도 잘되질않네요
    도움주신대로 시도는 계속해보겠습니다 감사합니다
댓글 입력 영역


Books

Geek라이프

게임 매니악스 슈팅 게임 알고리즘
마츠우라 켄이치로,츠카사 유키 공저/손정도 역/박민근,Pope Kim 감수

게임 매니악스 퍼즐 게임 알고리즘
마츠우라 켄이치로,츠카사 유키 공저/김병국 역

핵심강좌! Cocos2d-x
이재환 저

될 수 있어! SE 13
나츠미 코지 저/Ixy 그림/김경훈 역
예스24 | 애드온2