안드로이드 개발자 모임 게시판
(글 수 7,973)
안펍 세미나 동영상 from kevinkim on Vimeo.
전체 화면으로 보셔야 선명하게 보일듯 하네요.
이 동영상은 2배속으로 인코딩한겁니다. 실제로는 59분 걸렸어요.
디자인 하는데 20분 정도, 나머지는 코딩하는데 걸린 시간입니다.
세미나에 사용된 파워포인트 자료는 첨부파일로 올렸습니다.
슬라이드쇼로 보시면 됩니다.
소스는 아쉽게도 풀소스는 아닙니다만, 게임 부분 전체 소스를 넣었습니다.
- package beeniesoft.game.test;
- import java.util.Random;
- import javax.microedition.khronos.opengles.GL10;
- import android.content.*;
- import android.media.AudioManager;
- import android.media.MediaPlayer;
- import android.media.SoundPool;
- import android.os.Vibrator;
- import bayaba.game.lib.*;
- public class GameMain
- {
- class KeyStatus // 멀티터치를 위한 클래스
- {
- public int x = 0, y = 0;
- public boolean status = false;
- public void SetKey( int px, int py, boolean flag )
- {
- x = px;
- y = py;
- status = flag;
- }
- }
- public GL10 gl = null; // OpenGL 객체
- private static int MAX_GAME = 300; // 게임에서 사용할 오브젝트의 최대 개수 설정
- private int Sort[] = new int [MAX_GAME]; // 오브젝트 소팅을 위한 배열
- private int Data[] = new int [MAX_GAME];
- public boolean Pause = false, GameStart = false; // 포즈 상태 플래그, 게임 시작 플래그 변수
- private SoundPool SndPool;
- private MediaPlayer Music;
- private Vibrator Vibe;
- private int SndBuff[] = new int [20];
- public GameInfo gInfo; // 게임 환경 설정용 클래스 : MainActivity에 선언된 것을 전달 받는다.
- private Sprite Pattern[] = new Sprite [30]; // 스프라이트 파일을 읽어들일 클래스 배열
- private GameObject Game[] = new GameObject [MAX_GAME]; // 오브젝트를 처리할 클래스 배열
- public int GameMode = 0, TotalGame = 0, TotalButton = 0; // GameMode는 게임 화면의 상태, TotalGame은 실제로 화면에 뿌려질 오브젝트의 개수, TotalButton은 UI용 오브젝트의 개수
- private long QuakeTimer = 0; // 지진 효과가 지속될 시간 타이머
- private long TargetTimer = 0, ArrowTimer = 0;
- public boolean ArrowFlag = false, FireFlag = false;
- {
- int i;
- MainContext = context;
- gInfo = info;
- for ( i = 0; i < 30; i++ ) Pattern[i] = new Sprite(); // 스프라이트 파일을 담을 클래스 생성
- Music = MediaPlayer.create(context, R.raw.intro);
- Music.setLooping(false);
- SndPool = new SoundPool(5, AudioManager.STREAM_MUSIC, 0);
- SndBuff[1] = SndPool.load(context, R.raw.arrow, 1);
- SndBuff[2] = SndPool.load(context, R.raw.hit, 1);
- for ( i = 0; i < MAX_GAME; i++ ) // 게임 오브젝트 생성
- {
- Game[i] = new GameObject();
- Game[i].dead = true;
- Game[i].show = false;
- }
- }
- public void PlaySound( int num )
- {
- SndPool.play( SndBuff[num], 1f, 1f, 0, 0, 1f );
- }
- public void PlayVibe( int val )
- {
- Vibe.vibrate( val );
- }
- public void LoadLogoData() // 로고 화면을 보여준다.
- {
- Pattern[0].LoadSprite( gl, MainContext, R.drawable.logo, "back.spr" ); // logo 이미지를 불러와서 back.spr과 연결시킨다.
- TotalButton = 0;
- Button[TotalButton].SetObject( Pattern[0], 0, 0, 240, 400, 0, 0 ); // UI용 오브젝트에 로고 스프라이트의 0번 모션, 0번 프레임을 등록한다.
- GameMode = 0;
- }
- public void LoadGameData()
- {
- Pattern[0].LoadSprite( gl, MainContext, R.drawable.main, "main.spr" ); // main 이미지를 불러와서 main.spr과 연결시킨다.
- TotalGame = 0;
- Game[TotalGame].SetObject( Pattern[0], 0, 0, 240, 400, 0, 0 ); // 게임 오브젝트에 배경 스프라이트의 0번 모션, 0번 프레임을 등록한다.
- Game[TotalGame].trans = 0.0f; // 투명도를 0으로 설정해서 서서히 밝아지도록 한다.
- Game[TotalGame].scroll = false; // 화면 스크롤의 영향을 받지 않도록 한다.
- Game[TotalGame++].dead = false; // 살아있는 오브젝트로 선언한다.
- ArrowFlag = FireFlag = false; // 화살 및 발사 플래그 변수
- GameMode = 1;
- }
- public void PushButton() // 터치가 들어왔을때 호출되는 함수
- {
- int i, k;
- boolean flag;
- float x, y;
- if ( GameMode == 0 ) // 로고 화면일 때 아무 처리를 하지 않는다.
- {
- }
- else if ( GameMode == 1 ) // 게임 화면일 때
- {
- for ( i = 0; i < TotalButton; i++ ) // 멀티터치 처리영역 : 이 게임에선 쓰지 않음
- {
- flag = false;
- for ( k = 0; k < 5; k++ )
- {
- {
- }
- }
- if ( flag )
- {
- }
- }
- if ( System.currentTimeMillis()-ArrowTimer >= 500 ) FireFlag = true; // 타이머가 500 밀리세컨을 넘은 상태면 화살 발사가 가능하게 한다.
- }
- }
- private void Sort( int start, int count ) // 오브젝트 소팅 함수
- {
- int i = start, w, x, k = count;
- x = Sort[(start + count) / 2];
- while ( i <= k )
- {
- while ( Sort[i] < x ) i++;
- while ( Sort[k] > x ) k--;
- if ( i <= k )
- {
- w = Sort[i];
- Sort[i] = Sort[k];
- Sort[k] = w;
- w = Data[i];
- Data[i] = Data[k];
- Data[k] = w;
- i++; k--;
- }
- }
- if ( start <= k ) Sort( start, k );
- if ( i <= count ) Sort( i, count );
- }
- private void MakeTarget() // 타겟 생성 함수
- {
- if ( MyRand.nextInt(100) == 0 ) // 1% 확률로 화살을 생성
- {
- if ( System.currentTimeMillis()-TargetTimer >= 1500 ) // 1% 조건이 됐어도 마지막 화살을 생성한지 1.5초가 지나야 새로운 화살 생성이 가능하게 한다.
- {
- for ( int i = 0; i < MAX_GAME; i++ )
- {
- if ( Game[i].dead ) // 죽어있는 오브젝트들 중에서 선택
- {
- Game[i].SetObject( Pattern[0], 1, 1, 520, 400, 1, 0 ); // 타겟 오브젝트를 type 1로 , main.spr의 1번 모션, 0번 프레임으로 생성한다.
- Game[i].scroll = false; // 스크롤의 영향을 받지 않도록 한다.
- Game[i].dead = false; // 살아있는 오브젝트로 선언
- return;
- }
- }
- }
- }
- }
- private void MakeArrow() // 화살 생성 함수
- {
- if ( !ArrowFlag )
- {
- {
- for ( int i = 0; i < MAX_GAME; i++ )
- {
- if ( Game[i].dead ) // 죽어있는 오브젝트들 중에서 선택
- {
- ArrowFlag = true;
- Game[i].SetObject( Pattern[0], 2, 2, 240, 700, 3, 0 ); // 화살 오브젝트를 type 2로 , main.spr의 3번 모션, 0번 프레임으로 생성한다.
- Game[i].power = 2000; // 화살이 최초에 날아가는 중력 파워
- Game[i].scroll = false; // 스크롤의 영향을 받지 않도록 한다.
- Game[i].dead = false; // 살아있는 오브젝트로 선언
- return;
- }
- }
- }
- }
- }
- private void ZoomObject( GameObject sprite, float ratio ) // 오브젝트를 확대시킨다.
- {
- float sx = sprite.x2 - sprite.x1, sy = sprite.y2 - sprite.y1;
- sprite.zx += (sx * ratio) - sx;
- sprite.zy += (sy * ratio) - sy;
- }
- private void MakePiece( int k ) // 파편 생성 함수
- {
- int i, cnt = 0;
- for ( i = 0; i < MAX_GAME; i++ )
- {
- if ( Game[i].dead ) // 죽어있는 오브젝트들 중에서 선택
- {
- Game[i].SetObject( Pattern[0], 3, 3, Game[k].x, Game[k].y, 2, cnt ); // 파편 오브젝트를 type 3로 , main.spr의 2번 모션, cnt번 프레임으로 생성한다.
- Game[i].scroll = false; // 스크롤의 영향을 받지 않도록 한다.
- Game[i].direct = MyRand.nextInt( 360 ); // 파편이 날아갈 각도를 설정한다.
- Game[i].power = 600 + MyRand.nextInt( 600 ); // 날아갈 속도를 자연스럽게 보이도록 랜덤하게 설정한다.
- Game[i].PutSprite( gInfo ); // x1,y1,x2,y2 값을 계산한다. (확대를 위해)
- Game[i].dead = false; // 살아있는 오브젝트로 선언
- if ( ++cnt >= 10 ) return; // 파편이 10개 생성되면 그만둔다.
- }
- }
- }
- private void CheckTarget( int num ) // 화살과 타겟의 충돌 체크, num은 화살 오브젝트의 번호
- {
- int i, k;
- for ( k = 0; k < TotalGame; k++ ) // 게임에 있는 모든 오브젝트를 검사한다.
- {
- i = Data[k];
- if ( Game[i].type == 1 ) // 그중에 타겟 오브젝트만 검사한다.
- {
- Game[i].PutSprite( gInfo ); // 정확한 계산을 위해 x1,y1,x2,y2를 설정한다.
- if ( Game[num].x >= Game[i].x1 && Game[num].x <= Game[i].x2 ) // 화살이 타겟의 영역에 들어간 상태면
- {
- MakePiece( i ); // 파편 조각 생성 함수 호출
- PlaySound( 2 ); // 사운드 출력
- Game[i].show = false; // 타겟을 사라지게 한다.
- Game[i].dead = true; // 타겟을 삭제한다.
- return;
- }
- }
- }
- }
- private void UpdateGame() // 논리적인 오브젝트 처리 함수, 실제로 화면에 출력하진 않지만, 좌표, 크기 등을 미리 계산한다.
- {
- int i, k;
- float y;
- if ( GameMode == 0 ) // 로고 화면일때
- {
- {
- {
- Music.start(); // 로고 사운드를 출력한다.
- }
- }
- {
- }
- {
- {
- LoadGameData(); // 게임 로딩 함수 호출
- }
- }
- }
- else if ( GameMode == 1 ) // 게임 오브젝트 처리 영역
- {
- if ( !Pause )
- {
- TotalGame = 0;
- MakeTarget(); // 타겟 오브젝트 생성 함수 호출
- MakeArrow(); // 화살 오브젝트 생성 함수 호출
- for ( i = 0; i < MAX_GAME; i++ ) // 살아있는 모든 오브젝트를 검색한다.
- {
- if ( !Game[i].dead )
- {
- Data[TotalGame] = i;
- Sort[TotalGame] = (int)Game[i].layer;
- TotalGame++;
- }
- }
- Sort( 0, TotalGame - 1 ); // 소팅한다.
- for ( k = 0; k < TotalGame; k++ ) // 실제로 살아있는 오브젝트들만 처리한다.
- {
- i = Data[k];
- if ( Game[i].type == 0 ) // 배경 화면 오브젝트 처리
- {
- if ( Game[i].move == 0 )
- {
- Game[i].trans += 0.033f; // 배경이 서서히 보이도록 한다.
- if ( Game[i].trans >= 1 )
- {
- Game[i].trans = 1;
- Game[i].move = 1;
- }
- }
- }
- if ( Game[i].type == 1 ) // 타겟 오브젝트 처리 루틴
- {
- Game[i].x -= 2.0f; // 타겟이 오른쪽에서 왼쪽으로 2도트씩 움직이게 한다.
- if ( Game[i].x < -50 ) // 화면의 바깥으로 -50 위치 이하로 사라지면 오브젝트를 삭제한다.
- {
- Game[i].show = false; // 타겟을 안보이게 하고
- Game[i].dead = true; // 타겟을 삭제한다.
- }
- }
- if ( Game[i].type == 2 ) // 화살 오브젝트 처리 루틴
- {
- if ( Game[i].attack == 0 )
- {
- if ( FireFlag && ArrowFlag ) // 터치된 상태(FireFlag)이고, 화살이 생성된(ArrowFlag) 상태이면
- {
- PlaySound( 1 ); // 화살이 날아가는 사운드 출력
- Game[i].attack = 1; // 날아가는 루틴으로 이동
- }
- }
- else
- {
- y = Game[i].y; // 이전의 좌표를 기억해둔다
- Game[i].y -= Game[i].power / 100; // 화살이 날아가는 파워에 따라 y 좌표 계산
- Game[i].power -= 40; // 파워를 점점 감속시킨다.
- if ( Game[i].power < 500 ) Game[i].power = 500; // 화살의 감속 속도가 최대 500 이하로 내려가지 않게 한다.
- ZoomObject( Game[i], 0.99f ); // 화살을 10%씩 축소한다.
- if ( y >= 190 && Game[i].y <= 190 ) CheckTarget( i ); // 이전 좌표와 날아간 좌표가 타겟을 넘어간 상태면 충돌을 체크한다.
- if ( Game[i].y < 150 ) // y 좌표가 150 이하로 내려가면 화살을 삭제한다.
- {
- ArrowFlag = false; // 새로운 화살을 생성하게 한다.
- Game[i].show = false; // 화살을 보이기 않게 하고
- Game[i].dead = true; // 화살을 삭제한다.
- }
- }
- }
- if ( Game[i].type == 3 ) // 터질때 파편들
- {
- Game[i].x += (gInfo.SinTBL[Game[i].direct] * (Game[i].power / 100)); // x 좌표를 sin 값에 따라 지정된 각도로 이동한다.
- Game[i].y -= (gInfo.CosTBL[Game[i].direct] * (Game[i].power / 100)); // y 좌표를 cos 값에 따라 지정된 각도로 이동한다.
- Game[i].power -= 40; // 날아가는 파워를 감속시킨다.
- if ( Game[i].power < 100 ) Game[i].power = 100; // 파워가 100 이하로 떨어지지 않게 한다.
- ZoomObject( Game[i], 0.99f ); // 10%씩 축소시킨다.
- if ( Game[i].x2 - Game[i].x1 <= 5 ) // 축소되는 이미지의 가로 길이가 5도트 이하가 되면 삭제한다.
- {
- Game[i].show = false; // 파편을 안보이게 하고
- Game[i].dead = true; // 파편을 삭제한다.
- }
- }
- Game[i].PutSprite( gInfo ); // 좌표들을 재설정한다.
- }
- // 지진 효과 처리 루틴 - 이 게임에선 쓰지 않는다.
- {
- }
- else
- {
- gInfo.QuakeY = 0;
- }
- }
- }
- }
- public void DoGame() // 실제 OpenGL 렌더링 영역에서 호출되는 부분
- {
- int i, k;
- UpdateGame(); // 오브젝트의 논리적인 좌표 계산을 처리한다.
- if ( GameMode == 0 ) // 로고 처리
- {
- }
- else if ( GameMode == 1 ) // 게임 처리
- {
- for ( k = 0; k < TotalGame; k++ ) // 살아있는 모든 오브젝트를 그린다.
- {
- i = Data[k];
- Game[i].DrawSprite( gInfo ); // 실제로 화면에 그린다.
- }
- }
- }
- }
2012.04.22 21:22:16
동영상에 소스 코드가 안보여서 메인 소스만 좀 올리려고 하는데, 소스 올리는 방법 아시는 분? 그 왜 라인 번호 붙어서 이쁘게 소스 나오는거 있잖아요.
2012.04.22 21:46:46
와웅~ 연금술사?는 어떤거죠? 스프라이트 툴도 있고.. 많은 걸 제공하는군요
소스코드는 Code Highlighter 로 올리시면 됩니다.^^
제로보드 에디터 [확장 컴포넌트]에 있습니다.
소스를 일반텍스트로 쓰시구 드래그하신 후 Code Highlighter 컴포넌트 클릭하시면 됩니당~
2012.04.22 22:13:08
링크 주소에는 아무 것도 넣지 않으셔도 됩니다.
저도 바야바님 말씀듣고 해보려는데 크롬에서는 깨지네요ㅎㅎ
그래서 찾다가 요런걸 발견했어요
사용법은 여기에~ ㅎㅎ
2012.04.22 23:22:32
넹~~ 무지 잘 보입니다.
아 DMC에서 강연 해주신 툴이 요거였군요
멀어서 ㅜ 아쉽네요 체험해볼 수 있는 기회였는데
저도 디자인 겸하는 1인개발자라 엔진써서 생산성을 최대한 높여보고 있는데
아무래도 직접 만드신 엔진으로 개발하는 것하곤 많이 다르겠네요 ㅜ
이런 좋은 정보는 정보게시판에 ^^