기존에 사용하던 소스에서 Thread를 별도의 클래스로 빼냄.

GameMain.java
public class GameMain extends Activity {
/** Called when the activity is first created. */
	
	public static GLGameSurfaceView mGLView;
	public static GLGameRenderer mGLRenderer;
	public static GameThread mThread;
	
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); 
        
        mGLRenderer = new GLGameRenderer(this);
        mGLView = new GLGameSurfaceView(this);
        mThread = new GameThread(this);

        setContentView(mGLView);
        mGLView.setVisibility(View.VISIBLE);
        
        mThread.start();
    }
    
	@Override
	public void onPause() {
		mThread.pauseThread();
		super.onPause();
	}

	@Override
	public void onResume() {
		mThread.resumeThread();
		super.onResume();
	}
}

GLGameRenderer, GLGameSurfaceView, GameThread 객체를 생성하고 Thread를 시작한다.
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
 화면을 항상 켬


GLGameRenderer.java
package pe.berabue.game;

import javax.microedition.khronos.egl.*;
import javax.microedition.khronos.opengles.*;

import android.content.*;
import android.opengl.GLSurfaceView.Renderer;

public class GLGameRenderer implements Renderer
{

	public static Context context;

	public GLGameRenderer(Context context)
	{
		GLGameRenderer.context = context;
	}
	
	@Override
	public void onDrawFrame(GL10 gl)
	{
		gl.glClear(GL10.GL_COLOR_BUFFER_BIT|GL10.GL_DEPTH_BUFFER_BIT);
	}

	@Override
	public void onSurfaceChanged(GL10 gl, int width, int height)
	{
		gl.glOrthof(0.0f, 800.0f, 480.0f, 0.0f, 1.0f, -1.0f);
		gl.glMatrixMode(GL10.GL_MODELVIEW);
		gl.glViewport(0, 0, width, height);
		
		gl.glEnable(GL10.GL_TEXTURE_2D);
		gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
		gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
		gl.glEnable(GL10.GL_BLEND);
		gl.glBlendFunc(GL10.GL_ONE, GL10.GL_ONE_MINUS_SRC_ALPHA);
	}

	@Override
	public void onSurfaceCreated(GL10 gl, EGLConfig arg1)
	{
		gl.glClearDepthf(1.0f);
		gl.glDisable(GL10.GL_DEPTH_TEST);
		gl.glMatrixMode(GL10.GL_PROJECTION);
	}
}

onDrawFrame();
 지속적인 호출을 통해 그림을 그리는 부분.
onSurfaceChanged();
 화면이 바뀔때 호출
onSurfaceCreated();
 화면이 생성될때 호출


GLGameSurfaceView.java
package pe.berabue.game;

import android.content.*;
import android.opengl.*;
import android.view.*;

public class GLGameSurfaceView extends GLSurfaceView
{
	public GLGameSurfaceView(Context context)
	{
		super(context);
		setRenderer(GameMain.mGLRenderer);
		setRenderMode(RENDERMODE_WHEN_DIRTY); // One drawing
		setFocusableInTouchMode(true);
	}
	
	@Override
	public boolean onKeyDown(int keyCode, KeyEvent event) {
		return true;
	}

	@Override
	public boolean onTouchEvent(MotionEvent event) {
		return true;
	}
}

setRenderMode(RENDERMODE_WHEN_DIRTY);
 GLGameRenderer()의 onDrawFrame()을 1회 호출.



GameThread.java
package pe.berabue.game;

import android.content.*;

public class GameThread extends Thread 
{
	public static boolean isRun;
	public static boolean isWait;
	
	public GameThread(Context context)
	{
		isRun = true;
		isWait = false;
	}

	public synchronized void run()
	{
		while(isRun)
		{
			try
			{
				GameMain.mGLView.requestRender(); // onDrawFrame
				Thread.sleep(10);
			}
			catch (InterruptedException e1)
			{
				e1.printStackTrace();
			}
			if (isWait)
			{
				try
				{
					wait();
				}
				catch (Exception e)
				{
					// Ignore error
				}
			}
		}
	}
	
	/* Thread pause */
	public void pauseThread()
	{
		isWait = true;
		synchronized (this)
		{
			this.notify();
		}
	}

	/* Thread Resume */
	public void resumeThread()
	{
		isWait = false;
        synchronized (this)
        {
             this.notify();
        }
    }
}

GameMain.mGLView.requestRender();
 GLGameRenderer()의 onDrawFrame() 호출 





gl.glDisable(GL10.GL_DEPTH_TEST);
 A물체를 그리고, 그 위에 B물체를 그렸을때 먼저 그린 A가 B를 가리는 현상이 나타날 수 있다.
 위 메서드를 사용하면 정상적으로 먼저 그린 A보다 나중에 그린 B가 위쪽에 그려지게 된다.

gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
  두 버퍼를 지운다.

gl.glClearColor(float red, float green, float blue, float alpha);
 ARGB 색상으로 지운다. 

gl.glEnable(GL10.GL_TEXTURE_2D);
 텍스쳐를 활성화 시킨다.

gl.glTranslatef(0.0f, 0.0f, -5.0f);
 기본 좌표는 화면의 중심이다. 좌표계를 범위만큼 움직인다. x를 0만큼, y를 0만큼, z를 -5.0만큼 움직인다.
 z값이 음수 일때 안쪽으로 들어가며 양수 일때 액정 바깥쪽으로 올라온다.

gl.glRotatef(45.0f, 0.0f, 0.0f, 0.0f);
 x,y,z 축을 45도 회전시킨다.


gl.glLoadIdentity();
 좌표계를 초기화시킨다.

gl.glEnable(GL10.GL_SCISSOR_TEST);
gl.glScissor(x, y, width, height);
gl.glDisable(GL10.GL_SCISSOR_TEST); 

 4개의 점 x, y, width, height 부분의 영역만 렌더링한다.





텍스쳐 입히기( 이미지 덮어 씌우기 )
아래 내용은 100% 정확한 것이 아니며, 여기저기서 보고 실행해본 결과를 토대로 작성하였다.

기존 소스에서 몇 부분만 추가. Triangle 클래스는 사용하지 않고 Quad 클래스만 사용하여 연습해본다.


Quad.java
import java.nio.*;
import javax.microedition.khronos.opengles.*;
import android.content.*;
import android.graphics.*;
import android.opengl.*;

public class Quad extends Shape {
	
	private FloatBuffer vertexBuffer;
	private ShortBuffer indexBuffer;
	private FloatBuffer textureBuffer;
	
	private int[] textureName;
	
	private float[] vertices = {
			-0.5f	, 0.5f	, 0.0f, // 0, Left Top
			0.5f	, 0.5f	, 0.0f,	// 1, Right Top
			0.5f	, -0.5f	, 0.0f,	// 2, Right Bottom
			-0.5f	, -0.5f	, 0.0f	// 3, Left Bottom
	};

	private short[] index = {
		0, 1, 2,
		0, 2, 3
	};
	
	private float[] texture = {
		0.0f, 0.0f,
		0.0f, 1.0f,
		1.0f, 1.0f,
		1.0f, 0.0f
	};
	
	public Quad() {
		textureName = new int[1];

		vertexBuffer = getFloatBufferFromFloatArray(vertices);
		indexBuffer = getByteBufferFromByteArray(index);
		textureBuffer = getFloatBufferFromTextureArray(texture);
	}

	/* Draw */
	public void draw(GL10 gl) {

		gl.glFrontFace(GL10.GL_CW);
		
		gl.glVertexPointer(3, GL10.GL_FLOAT, 0, vertexBuffer);
		gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, textureBuffer);
		
		gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
		gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
		
		gl.glDrawElements(GL10.GL_TRIANGLE_STRIP, index.length, GL10.GL_UNSIGNED_SHORT, indexBuffer);
		
		gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);		
		gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
	}
	
	/* Initialize Texture */
	public void InitTexture(GL10 gl, Context context) {

		Bitmap imgPanda = BitmapFactory.decodeResource(context.getResources(), R.drawable.panda);

		gl.glGenTextures(1, textureName, 0);					// 텍스쳐 포인터 설정
		gl.glBindTexture(GL10.GL_TEXTURE_2D, textureName[0]);	// 텍스쳐 사용 연결

		gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_NEAREST);
		gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR);

		GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, imgPanda, 0);
		
		imgPanda.recycle();
	}
}
우선 추가된 부분을 보면.
FloatBuffer textureBuffer;
 텍스쳐 버퍼.
 
int[] textureName;
 텍스쳐 포인터를 담는다.
 
float[] texture;
 텍스쳐 좌표. 좌표를 어떻게 하느냐에 따라 이미지가 이상하게 붙어버린다.
 어떤 순서로 붙는지 모르겠다. 


InitTexture();
  GLGameRenderer.java 에서 접근.
  우선 Bitmap 이미지를 가져온다.
  주의할점!! 이미지의 가로, 세로 길이가 '2의 배수'가 아니면 이미지가 나오지않는다.
 
 gl.glGenTextures(1, textureName, 0);
  텍스쳐 포인터 생성.
 
 gl.glBindTexture(GL10.GL_TEXTURE_2D, textureName[0]);
  텍스쳐 연결.
 
 gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_NEAREST);
 gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR); 
  이미지 자동 확대, 축소.

 GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, imgPanda, 0); 
  비트맵을 OpenGL 텍스쳐로 변경.

 
Draw();
 gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, textureBuffer);
  텍스쳐 좌표 설정.
 
 gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
  텍스쳐 활성화.
 
 gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
  비활성화.




이전까지와는 다르게 텍스쳐 버퍼가 추가되었다.

Shape.java
import java.nio.*;

public class Shape {

	FloatBuffer getFloatBufferFromFloatArray(float array[]) {
		ByteBuffer tempBuffer = ByteBuffer.allocateDirect(array.length * 4);
		tempBuffer.order(ByteOrder.nativeOrder());
		FloatBuffer buffer = tempBuffer.asFloatBuffer();
		buffer.put(array);
		buffer.position(0);
		return buffer;
	}
	
	ShortBuffer getByteBufferFromByteArray(short[] index) {
		ByteBuffer b = ByteBuffer.allocateDirect(index.length * 2);
		b.order(ByteOrder.nativeOrder());
		ShortBuffer buffer = b.asShortBuffer();
		buffer.put(index);
		buffer.position(0);
		return buffer;
	}
	
	FloatBuffer getFloatBufferFromTextureArray(float texture[]) {
		ByteBuffer tbb = ByteBuffer.allocateDirect(texture.length * 4);
		tbb.order(ByteOrder.nativeOrder());
		FloatBuffer buffer = tbb.asFloatBuffer();
		buffer.put(texture);
		buffer.position(0);
		return buffer;
	}
}
버퍼............



GLGameRenderer.java
@Override
	public void onDrawFrame(GL10 gl) {
		gl.glClear(GL10.GL_COLOR_BUFFER_BIT);//|GL10.GL_DEPTH_BUFFER_BIT);
		gl.glLoadIdentity();
		
	//	mTriangle.draw(gl);
		mQuad.draw(gl);
	}

	@Override
	public void onSurfaceCreated(GL10 gl, EGLConfig arg1) {
		mQuad.InitTexture(gl, context);

		gl.glClearColor(0, 1, 0, 0.5f);										// RGBA
		gl.glEnable(GL10.GL_TEXTURE_2D);									// 텍스쳐 활성
		gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_FASTEST);	// ??	
	}
onSurfaceCreated();
 mQuad.InitTexture(gl, context);   텍스쳐 초기화.
 
gl.glEnable(GL10.GL_TEXTURE_2D);   텍스쳐를 활성화 시킨다.





삼각형과 사각형을 그려볼 차례다.

아래 코드 실행시 삼각형과 사각형이 겹쳐서 나온다... 좌표 바꾸기가 귀찮아서.. 

 

GLGameRenderer.java

public class GLGameRenderer implements Renderer {

	private Triangle mTriangle;
	private Quad mQuad;
	
	public GLGameRenderer(Context context) {
		mTriangle = new Triangle();
		mQuad = new Quad();
	}
	
	@Override
	public void onDrawFrame(GL10 gl) {
		gl.glClear(GL10.GL_COLOR_BUFFER_BIT);	// 화면을 깨끗하게
		gl.glLoadIdentity();
		
		mTriangle.draw(gl);
		mQuad.draw(gl);
	}

	@Override
	public void onSurfaceChanged(GL10 gl, int width, int height) {
		gl.glViewport(0, 0, width, height);		// 화면크기 지정
	}

	@Override
	public void onSurfaceCreated(GL10 gl, EGLConfig arg1) {
		gl.glClearColor(0, 1, 0, 0.5f);										// RGBA
		gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_FASTEST);	// ??
	}
}

Triangle, Quad 객체를 생성한다.
onDrawFrame();
 생성한 객체의 draw 메서드를 통해 그림을 그린다.



Triangle.java
import java.nio.*;
import javax.microedition.khronos.opengles.*;

public class Triangle extends Shape {
	
	private FloatBuffer vertexBuffer;
	
	private float[] vertices = {
			0.0f	, 1.0f	, 0.0f,	// 0, Top
			1.0f	, -1.0f	, 0.0f, // 1, Right Bottom
			-1.0f	, -1.0f	, 0.0f 	// 2, Left Bottom
	};
	
	public Triangle() {
		vertexBuffer = getFloatBufferFromFloatArray(vertices);
	}
	
	/* 그리기 */
	public void draw(GL10 gl) {
		gl.glFrontFace(GL10.GL_CW);									// 시계 방향
		gl.glVertexPointer(3, GL10.GL_FLOAT, 0, vertexBuffer);		// 버퍼 포인터
		gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);				// 버퍼 활성화
		gl.glDrawArrays(GL10.GL_TRIANGLES, 0, 3);					// 그린다
		gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);				// 버퍼 비활성화
	}
}

vertices[];
 삼각형을 이루는 꼭지점 3개를 지정한다.
 좌표는 핸드폰 중심을 기준으로 상하좌우 0.0f ~ 1.0f. ( 1.0f는 화면 끝점이 된다. )
 
vertexBuffer = getFloatBufferFromFloatArray(vertices);
 버퍼부분은 어떻게 돌아가는지 모르겠지만 공식과도 같다한다.

gl.glFrontFace(GL10.GL_CW);
 각 꼭지점을 시계방향으로 그린다. 0 -> 1 -> 2 순서로 그림.
 GL_CCW - 반시계 방향.

gl.glVertexPointer(3, GL10.GL_FLOAT, 0, vertexBuffer);
 
꼭지점 값이 있는 실수형 버퍼를 넣는다.

gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);

 꼭지점 배열값을 사용해 그린다.

gl.glDrawArrays(GL10.GL_TRIANGLES, 0, 3)
;
 도형 내부가 채워진 삼각형을 그린다.
 GL_LINE_LOOP - 도형을 선으로 표현
 GL_POINTS - 도형을 점으로 표현

gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);

 그리기 종료(?)



Quad.java
import java.nio.*;
import javax.microedition.khronos.opengles.*;

public class Quad extends Shape {
	
	private FloatBuffer vertexBuffer;
	private ByteBuffer indexBuffer;
	
	private float[] vertices = {
			-0.5f	, 0.5f	, 0.0f, // 0, Left Top
			0.5f	, 0.5f	, 0.0f,	// 1, Right Top
			0.5f	, -0.5f	, 0.0f,	// 2, Right Bottom
			-0.5f	, -0.5f	, 0.0f	// 3, Left Bottom
	};
	private byte[] index = {
		0, 1, 2,
		0, 2, 3
	};
	
	public Quad() {
		vertexBuffer = getFloatBufferFromFloatArray(vertices);
		indexBuffer = getByteBufferFromByteArray(index);
	}
	
	void draw(GL10 gl) {
		gl.glFrontFace(GL10.GL_CW);
		gl.glVertexPointer(3, GL10.GL_FLOAT, 0, vertexBuffer);
		gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
		gl.glDrawElements(GL10.GL_TRIANGLES, index.length, GL10.GL_UNSIGNED_BYTE, indexBuffer);
		gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);		
	}
}
OpenGL은 도형을 그릴때 삼각형을 모아서 다른 도형을 그린다고 한다.
우선 사각형을 이루는 4개의 꼭지점을 지정한다.
index[];
 꼭지점을 어떻게 삼각형으로 만들지 정한다.
 3개의 꼭지점( 0, 1, 2 )을 연결해 하나의 삼각형으로 만들고, 또다른 삼각형( 0, 2, 3 )을 만든다.

삼각형과는 다르게 indexBuffer도 필요하다.

그려지는 부분또한 삼각형이랑 다른데..
gl.glDrawElements(GL10.GL_TRIANGLES, index.length, GL10.GL_UNSIGNED_BYTE, indexBuffer);
 index 개수와 indexBuffer를 넣는다.


 
Shape.java
import java.nio.*;

public class Shape {

	FloatBuffer getFloatBufferFromFloatArray(float array[]) {
		ByteBuffer tempBuffer = ByteBuffer.allocateDirect(array.length * 4);
		tempBuffer.order(ByteOrder.nativeOrder());
		FloatBuffer buffer = tempBuffer.asFloatBuffer();
		buffer.put(array);
		buffer.position(0);
		return buffer;
	}
	
	ByteBuffer getByteBufferFromByteArray(byte array[]) {
		ByteBuffer buffer = ByteBuffer.allocateDirect(array.length);
		buffer.put(array);
		buffer.position(0);
		return buffer;
	}
}
버퍼 부분.. 잘 모름...... 아무나 가르쳐줘요 ~ ~ ~


 





MapManager.java의 mListener 부분에 추가시켜준다.
    		sAddress = "";
    		sAddress = getGeocode(location.getLatitude(), location.getLongitude()); // 주소 받아옴
    		Toast.makeText(contxet, ""+sAddress, Toast.LENGTH_SHORT).show();
위치 정보를 받아오면 해당 위치의 주소를 반환시킨다.


MapManager.java에 추가시켜준다.
/* 주소 검색 */
	private String getGeocode(double ALatitude, double ALongitude) {
		String sResult = "";

    	Geocoder mGeocoder = new Geocoder(contxet);
        try {
            Iterator
mAddresses = mGeocoder.getFromLocation(ALatitude, ALongitude, 1).iterator(); if (mAddresses != null) { while (mAddresses.hasNext()) { Address namedLoc = mAddresses.next(); String addLine = namedLoc.getAddressLine(0); sResult += String.format("%s\n", addLine); } } return sResult; } catch (IOException e) { return "주소 검색 실패"; } } // getGeocode
위치 정보 수신시 접근. 주소를 반환한다.
getFromLocation(위도, 경도, 1~5); 3번째 인자값이 커지면 더 많은 주소를 반환. 



'Android > Etc.' 카테고리의 다른 글

정적 라이브러리 만들기  (0) 2012.09.25
Max OS에서 NDK 개발하기  (1) 2012.07.04
Orientation 고정, 키보드 숨기기  (0) 2011.04.17
멀티터치 구현하기  (0) 2011.03.16
Permission  (0) 2011.01.26



추가 파일
MapManager.java : 위치 찾기
DialogManager.java : 다이얼로그 관리


MainActivity에 MapManager 인스턴스 생성.

MapManager.java
import android.content.Context;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;
import com.google.android.maps.GeoPoint;
import com.google.android.maps.MapController;

public class MapManager {

	private DialogManager mDialogManager;
	private MapController mMapController;
	private LocationManager mLocationManager;
	private String mProvider;					// 공급자
	
	public MapManager(Context context) {
		mDialogManager = new DialogManager(context);
		
		mMapController = MyGps.mMapController;
		
		mLocationManager = (LocationManager)context.getSystemService(context.LOCATION_SERVICE);
	//	mProvider = mLocationManager.GPS_PROVIDER; 				// GPS
		mProvider = mLocationManager.NETWORK_PROVIDER;			// NETWORK
	}
	
	/* 위치 찾기 */
	public void SearchLocation() {
		mLocationManager.requestLocationUpdates(mProvider, 1000, 0, mListener);
		mDialogManager.Loading();
	}
	
    LocationListener mListener = new LocationListener() {
    	public void onLocationChanged(Location location) {
    		GeoPoint point = new GeoPoint((int)(location.getLatitude()*1E6), (int)(location.getLongitude()*1E6));
    		mMapController.animateTo(point); 									// 위치로 이동
    		mLocationManager.removeUpdates(mListener);							// 해제
    		mDialogManager.LoadingEnd();
    	}

    	public void onProviderDisabled(String provider) {
    		// 추가 : 공급자 사용불가 처리
    	}

    	public void onProviderEnabled(String provider) {
    	}

    	public void onStatusChanged(String provider, int status, Bundle extras) {
    	}
	}; // mListener
}
- mProvider : 공급자 선택 ( GPS를 사용하면 더욱 정확한 위치 확인가능. )
mLocationManager.requestLocationUpdates(mProvider, 1000, 0, mListener); (공급자, 1초, 0m, mListener);  시간과 거리는 AND가 아닌 OR. ex) 100초, 1000m 일경우, 1000m를 움직이지 않아도 100초 후에는 자동으로 갱신이 된다. 
- MainActivity에서 만든 메뉴 1번에 SearchLocation();을 연결한다. 메뉴 선택 후 '위치찾기'시 위치를 찾는중이라는 다이얼로그를 띄워준다. 
 위치를 찾으면 다이얼로그와 위치찾기를 해제시킨다. ( 배터리 소모 방지 ) 


DialogManager.java
import android.app.ProgressDialog;
import android.content.Context;

public class DialogManager {

	private Context context;
	private ProgressDialog mProgressDialog;
	
	public DialogManager(Context context) {
		this.context = context;
	}
	
	/* loading 구현*/
    public void Loading() {
    	mProgressDialog = ProgressDialog.show(context, null, "위치 정보 받는중...", true, false);
    }
    
    /* loading 끝 */
    public void LoadingEnd() {
    	mProgressDialog.dismiss();
    }
}
위치를 찾을때는 보여주고, 찾고 난 후 제거해 준다.





타이틀바를 없애도 풀스크린 사용.
단말기를 기울였을때 화면을 바꾸고 싶지 않거나, 쿼티자판을 뺏을때 화면이 갱신되는 것을 막는다.

<application android:icon="@drawable/icon" android:label="@string/app_name">
<activity android:name="Test" 
android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
android:screenorientation="landscape" android:configchanges="orientation|keyboardHidden">
</activity>
</application>



'Android > Etc.' 카테고리의 다른 글

Max OS에서 NDK 개발하기  (1) 2012.07.04
넥서스S USB 드라이버 다운  (0) 2011.04.18
멀티터치 구현하기  (0) 2011.03.16
Permission  (0) 2011.01.26
데이터 저장 (SharedPreferences)  (0) 2011.01.25



enGLTest.java - 메인 액티비티
package pe.berabue.opengl;

import android.app.*;
import android.os.*;
import android.view.*;

public class OpenGLTest extends Activity {
    /** Called when the activity is first created. */
	
	public static GLGameSurfaceView mGLView;
	public static GLGameRenderer mGLRenderer;
	
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // 조명 항상켜기
         getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); 
        
        mGLRenderer = new GLGameRenderer(this);
        mGLView = new GLGameSurfaceView(this);
        setContentView(mGLView);
    }
    
	@Override
	public void onPause() {
		mGLView.mGameThread.pauseThread();
		super.onPause();
	}

	@Override
	public void onResume() {
		mGLView.mGameThread.resumeThread();
		super.onResume();
	}
}


GLGameSurfaceView.java - 쓰레드가 있는 부분 
package pe.berabue.opengl;

import android.content.*;
import android.opengl.*;
import android.util.*;
import android.view.*;

public class GLGameSurfaceView extends GLSurfaceView{
	
	public static GameThread mGameThread;

	public static boolean isRun;
	public static boolean isWait;
	
	public GLGameSurfaceView(Context context) {
		super(context);
		setRenderer(OpenGLTest.mGLRenderer);
		setRenderMode(RENDERMODE_WHEN_DIRTY); // 한번만 그려줌
		setFocusableInTouchMode(true);
		
		mGameThread = new GameThread(context);
		mGameThread.start();
	}
	
	@Override
	public boolean onKeyDown(int keyCode, KeyEvent event) {
		Log.v(null,"onKeyDown");
		return super.onKeyDown(keyCode, event);
	}

	@Override
	public boolean onTouchEvent(MotionEvent event) {
		Log.v(null,"onTouchEvent");
		return super.onTouchEvent(event);
	}
	
	// Thread
	public class GameThread extends Thread {

		public GameThread(Context context) {
			isRun = true;
			isWait = false;
		}

		public void run() {
			while(isRun) {
				try {
					OpenGLTest.mGLView.requestRender(); // onDrawFrame
					mGameThread.sleep(10);
				} catch (InterruptedException e1) {
					e1.printStackTrace();
				}
				synchronized (this) {
					if (isWait) {
						try { wait(); } catch (Exception e) {
							// 에러 무시
						}
	                }
				}//syn
			}
		}
		
		/* Thread pause */
		public void pauseThread() {
			isWait = true;
			synchronized (this) {
				this.notify();
			}
		}

		/* Thread Resume */
		public void resumeThread() {
			isWait = false;
	        synchronized (this) {
	             this.notify();
	        }
	    }
	}
}
setRenderMode(RENDERMODE_WHEN_DIRTY); 
GLGameRenderer의 그려주는 부분에서 1회만 그려준다. 파라메터를 RENDERMODE_CONTINUOUSLY로 바꿀 경우 계속 그리기.
1회만 그리는 이유는 멀티쓰레드를 사용하여 원활한 키 입력이나 터치를 받기 위해서 라는데.. 동기화는 다음에 생각하기로...

OpenGLTest.mGLView.requestRender();
requestRender();는 onDrawFrame();을 호출한다. GLGameRenderer의 onDrawFrame();호출.


GLGameRenderer.java - 실제로 그려지는 부분
package pe.berabue.opengl;

import javax.microedition.khronos.egl.*;
import javax.microedition.khronos.opengles.*;

import android.content.*;
import android.opengl.GLSurfaceView.Renderer;
import android.opengl.*;

public class GLGameRenderer implements Renderer {

	public GLGameRenderer(Context context) {
		
	}
	
	@Override
	public void onDrawFrame(GL10 gl) {
		gl.glClear(GL10.GL_COLOR_BUFFER_BIT|GL10.GL_DEPTH_BUFFER_BIT);
		// 실제 그려지는 부분..
	}

	@Override
	public void onSurfaceChanged(GL10 gl, int width, int height) {
		
	}

	@Override
	public void onSurfaceCreated(GL10 gl, EGLConfig arg1) {
		gl.glClearColor(0, 1, 0, 0.5f);	// RGBA 배경화면  0-> 1 점점밝아짐
		gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_FASTEST);	// ??
	}

}

Renderer을 구현(implemets)하게되면 기본적으로 위 3개의 메서드를 추가해야 된다.
onDrawFrame(); 실제로 그려지는 부분. 이 부분을 주기적으로 호출해 그림을 그려준다.
onSurfaceChanged(); 화면이 바뀔때 실행되는 부분.(실행시, orientation이 변경될때 등)
onSurfaceCreated(); 처음 실행 후 만들어질때 실행된다. (홈키를 누르거나 전화를 받고 다시 화면이 나올때도 실행)


GLGameRenderer에 조금 더 추가하면 기본적인 틀이 완성. 오늘은 여기까지.


실행화면

 

 




최종목표 : OpenGL을 사용하여 안드로이드용 간단한 2D, 3D 게임 만들기.


이      름 : 레인보우팡팡
장      르 : 퍼즐
가      격 : 1,500원
언      어 : 한국어/ 영어
지원버전 : 안드로이드OS  2.1이상
마      켓 : OZ스토어 / T스토어

※ 게임방법!
  일직선상에 같은 색상을 가진 버섯이 3마리 이상 되도록 해야해요.
  버섯이 이동 후 폭발하지 않으면 다시 제자리로 돌아와요.
  주어진 시간안에 스테이지를 끝내지 못하면 버섯이 번지를 해요 ㅜ ㅜ
 
※ 미션!
  스테이지가 올라갈수록 더 많은 버섯을 없애야 미션을 성공시킬 수 있어요.

※ 아이템!
  일정 확률로 4가지의 아이템이 나와요.
  아이템은 스테이지가 끝나면 사라지니 아낌없이 사용하세요!



---------------------------------------------------------------------

담당 역할

- 기획, 개발 및 약간의 디자인

'프로젝트' 카테고리의 다른 글

[T스토어] 이상한 나라의 사천성  (0) 2011.11.06
[OZ스토어/T스토어] CrazyPanda 크레이지판다  (0) 2011.01.25
[GNEX, WIPI] 스도쿠  (0) 2011.01.03
[WIPI] 풍선 타이쿤  (0) 2011.01.03
[GNEX] 스포츠 천국  (0) 2011.01.03

멀티터치는 2.1 이상의 버전에서 구현 가능하다.

	/* onTouch Event */
	public boolean onTouchEvent(MotionEvent e) {
		if ( e.getAction() == MotionEvent.ACTION_DOWN || e.getAction() == MotionEvent.ACTION_MOVE ) {
			int touchCount = e.getPointerCount();
						
			if ( touchCount > 1 ) {
				x1 = (int)e.getX(1);
				y1 = (int)e.getY(1);
			}
			else {
				x = (int)e.getX(0);
				y = (int)e.getY(0);
			}
		}
		return true;
	} // Touch Event 끝

간단한코드. e.getPointerCount()를 사용하여 몇개가 터치되고 있는지를 받아온다.
위 소스는 두개만을 받아왔다.
리스트를 사용하면 최대 지원가능한 수 까지 받아올 수 있을듯.

'Android > Etc.' 카테고리의 다른 글

Max OS에서 NDK 개발하기  (1) 2012.07.04
넥서스S USB 드라이버 다운  (0) 2011.04.18
Orientation 고정, 키보드 숨기기  (0) 2011.04.17
Permission  (0) 2011.01.26
데이터 저장 (SharedPreferences)  (0) 2011.01.25

국내 광고는 카울리를 적용시켰지만, 해외 판매 앱에 한글 광고를 달 수 없어 애드몹을 적용 시켰다.

Admob 가입 : http://www.admob.com

가입은 생각보다 어렵지 않다. 주소는 녹색창에 'xx시 영문 주소'를 쳤더니 다 나온다.

언어선택 : 홈페이지언어. 한국어가 추가된지 얼마 안된것 같음.

가입 후 MarketPlace -> Add Site/App -> SDK 다운로드(PDF) -> Go to Sites/Apps
원하는 앱의 Manage Settings을 보면 Publisher ID: xxxxxxxxxxxxxxx 15자리의 고유 ID가 생성


먼저 프로젝트 우 클릭 후 Properties -> Java Build Path -> Libraries -> Add External JARs -> 다운받은 SDK, Jar 파일 등록


다운받은 PDF 파일을 보고 보이는 소스만 적당한 위치에 모두 넣어준다.

에뮬 테스트 소스 전까지만. 정상 작동 확인.

영어라 왜 넣는지 모르는 부분이 있는데 나중에 봐야겠다....

'Android > 광고' 카테고리의 다른 글

카울리 적용방법 1.1.5  (1) 2011.03.07

카울리 가입하기 : http://www.cauly.net

APP관리 -> APP등록

APP등록을 완료하면 SDK다운로드와 해당 앱에 특정 코드가 발급됨.


가이드를 보면, lib 폴더를 생성 후 CaulySDK-V1.1.5.jar 파일을 넣으라고 되어있는데
그냥 프로젝트 우클릭 -> Properties -> 다운받은 CaulySDK-V1.1.5.jar 파일을 Libraries로 추가



그 다음은 매니페스트에 퍼미션을 추가해 주어야하는데 가이드에 있는 그대로 복사를 하고 확인을 안했다가
오류가 생겨서 한참을 해매버렸다..
LogCat에 나오는 오류는
Caused by: android.view.InflateException: Binary XML file line #19: Error inflating class com.cauly.android.ad.AdView
증상은 앱을 실행시 바로 종료가 되는 현상.





위 구문이 가이드 그대로.. 잘보면 4번째와 5번째 퍼미션 " 앞에 공백이 들어가있다.

위 부분때문에 위 에러가 생겼는데 한참을 찾았다.


그 다음은 values 폴더에attrs.xml 파일을 추가시켜 <resources></resources> 사이에 가이드 내용을 넣어준다.


마지막으로 원하는 레이아웃 위치에 가이드에 있는 [CPC Sample Code] 부분을 추가시킨다.
xmlns:app=http://schemas.android.com/apk/res/com.cauly.adtest
app:appcode="CAULY"


위 부분에서 res/해당APP의 패키지명으로 바꾸고
appcode 부분에 처음에 APP등록을 마치고 받았던 코드를 입력해주면 끝.

앱을 실행시켜보면 광고가 뜨는데, 가끔 안뜰 때도 있는것 같다.

'Android > 광고' 카테고리의 다른 글

애드몹(Admob) 적용방법  (0) 2011.03.08
		
		String dirPath = getFilesDir().getAbsolutePath(); 
		File file = new File(dirPath); 
		
		// 일치하는 폴더가 없으면 생성
		if( !file.exists() ) {
			file.mkdirs();
			Toast.makeText(this, "Success", Toast.LENGTH_SHORT).show();
		}
		
		// txt 파일 생성
		String testStr = "ABCDEFGHIJK...";
		File savefile = new File(dirPath+"/test.txt");
		try{
			FileOutputStream fos = new FileOutputStream(savefile);
			fos.write(testStr.getBytes());
			fos.close();
			Toast.makeText(this, "Save Success", Toast.LENGTH_SHORT).show();
		} catch(IOException e){}
		
		// 파일이 1개 이상이면 파일 이름 출력
		if ( file.listFiles().length > 0 )
    		for ( File f : file.listFiles() ) {
    			String str = f.getName();
    			Log.v(null,"fileName : "+str);
    			
    			// 파일 내용 읽어오기
    			String loadPath = dirPath+"/"+str;
    			try {
    				FileInputStream fis = new FileInputStream(loadPath);
    			    BufferedReader bufferReader = new BufferedReader(new InputStreamReader(fis));
    				
    			    String content="", temp="";
    				while( (temp = bufferReader.readLine()) != null ) {
    					content += temp;
    				}
    				Log.v(null,""+content);
    			} catch (Exception e) {}
    		}


LogCat 결과




총 50장의 패를 두 명이 각각 10장씩 나누어 갖고 바닥에 8장을 놓는다.
첫 게임이라면 바닥의 패를 뒤집어 놓고 하나씩 골라서 높은 수(월)이 나오면 선이 되고
이후부터는 승자가 선이된다.

자신이 낸 패가 바닥의 패와 같은 패(월)이라면 가져갈 수 있다.
패를 낸 뒤 뒤집어져있는 맨 위의 패를 오픈해 바닥의 패와 비교해 가져 갈 수 있다.


여러 가지 상황.

뻑.
바닥의 패와 같은 무늬의 패를 냈는데 뒤집은 패가 동일한 무늬일때.('뻑', '쌌다' 라고도 표현)
<- 바닥의 패 <- 자신이 낸 패 <- 뒤집은 패

패를 가져갈 수 없으며, 바닥에 놔야한다.
상대방이 먹을 경우 - 상대방에게 피 한장을 주어야 함.
자뻑 : 자신이 싼 패를 자신이 먹는 경우 - 상대방의 피 두 장을 가져온다.
첫뻑 : 첫 순서에서 뻑을 할 경우 - 상대방에게 7점에 해당되는 금액을 받는다.
2연뻑 : 2연속으로 뻑을 할 경우 - 상대방에게 14점에 해당되는 금액을 받는다.
3연뻑 : 3연속으로 뻑을 할 경우 - 상대방에게 21점에 해당되는 금액을 받는다.
한 게임에서 3번의 뻑을 하게되면 7점으로 인정하여 게임이 끝난다.


따닥.
<- 바닥의 패 <- 자신이 낸 패 <- 뒤집은 패  

바닥에 같은 무늬의 패가 2장이 있고, 자신이 낸 패와 뒤집은 패가 모두 같은 무늬일 경우.
4장을 모두 가져가며, 상대방에게 피 한 장을 받는다.
첫따닥일 경우 상대방에게 7점에 해당되는 금액을 받는다.


판쓰리.
바닥에 있는 패를 모두 가져가 경우.('쓸' 이라고도 표현)
상대방에게 피 한장을 받는다.


폭탄, 흔들기.
<- 자신의 패 <- 바닥의 패
같은 무늬의 패 3장을 갖고 있고, 바닥에 같은 무늬의 패가 한장 있을때
3장을 동시에 내면 '폭탄'.
폭탄을 한 경우에는 두 장의 피를 먼저 내었기 때문에 두 장의 피(폭탄모양)가 생긴다.
나중에 패를 내지 않고 뒤집어져 있는 패를 두 번 오픈 시킬 수 있다.
폭탄 사용 시 상대방에게 피 한장을 받는다.
만약, 같은 무늬의 패 3장을 갖고 있지만 바닥에 같은 무늬의 패가 없다면
'흔들기'라고 하여 3장을 패를 모두 오픈시키고 한장씩 낼 수 있다.
두 상황 모두 승리시 최종점수 x2


쪽.
바닥에 없는 패를 내고 뒤집혀있는 패를 한장 오픈했을때 같은 무늬의 패가 나온경우.
상대방에게 피 한장을 받는다. ( 마지막 패 제외 )



'Etc' 카테고리의 다른 글

[ 맞고 ] 점수계산  (0) 2011.02.15
[ 맞고 ] 족보  (0) 2011.02.14



고.
1고, 2고는 1점씩 추가.
3고부터 고를 할때마다 최종점수 x2

폭탄. 흔들기.
1번 할때마다 최종점수 x2

멍따.
열끗이 7장 이상이면 최종점수 x2

독박.
고를 한 상태에서 상대방이 스톱을 한 경우.
내 점수 + 상대방 점수 = 자신이 물어야 함.

피박.
피 10장 이상으로 이겻을 때 상대방의 피가 7장 이하면 최종점수 x2

광박.
광 3장 이상으로 이겻을 때 상대방이 광을 한 장도가지고 있지 못하면 최종점수 x2

나가리.
더 이상 패가 없을때, 아무도 7점을 내지 못하거나
상대방이 고를 하였지만 패를 모두 소모할 때 까지 추가 점수를 내지 못했을때
다음 판에서 무조건 x2

총통.
같은 무늬의 패가 4개를 모두 소지. 10점.
그 상태에서 고를 할 수도 스톱을 할 수도 있다.



'Etc' 카테고리의 다른 글

[ 맞고 ] 게임방법  (0) 2011.02.15
[ 맞고 ] 족보  (0) 2011.02.14



         
1월                                              2월                                              3월
         
4월                                              5월                                              6월
         
7월                                              8월                                              9월
         
 10월                                            11월                                            12월
 +
보너스 패 2장

게임시작. 총 50장의 패를 10장씩 나누어 갖고 바닥에 8장을 오픈한 상태에서 시작한다.


족보.

광.
 
'光' 이 새겨져 있는 패.
광 3장을 모으면 3점이고 5번째 그림인 비광을 포함하여 3장을 모으면 2점.
광을 4장모으면 4점, 5장을 모두 모으면 15점이다.


열끗.

기본 패 모양에 동물 그림이 추가되어 있는 패.
5장을 모으면 1점이며, 1장이 추가 될 때마다 1점씩 더해진다.
총 7장 이상을 모으면 멍따(멍텅구리 따블)이 되며 점수 계산시 x2


열끗 중 위 3개의 패를 모으면 고도리. 5점


띠.
              
기본 패 모양에 띠 그림이 추가되어 있는 패.
5장을 모으면 1점이며, 1장이 추가 될 때마다 1점씩 더해진다.
위 그림의 붙어있는 3장의 이름을 '홍단', '초단', '청단' 이라고 부른다. 3장을 모으면 3점 추가.
마지막 패는 초단이 될 수 없다.


피.


1월 부터 11월까지 2장씩 총 22개.
10장을 모으면 1점이며, 1장이 추가 될 때마다 1점씩 더해진다.


쌍피.
 + 보너스 패 2장.
왼쪽 두장은 쌍피로 피2장의 효과가 있으며, 3번째 패는 열끗과 피 둘중 하나로 사용 할 수 있다.
보너스 패는 피2장의 효과와 3장의 효과를 같는 두 개의 패가 존재.



'Etc' 카테고리의 다른 글

[ 맞고 ] 게임방법  (0) 2011.02.15
[ 맞고 ] 점수계산  (0) 2011.02.15
		if ( Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
			String path = Environment.getExternalStorageDirectory()+"/android/data/pe.berabue.maptools/.image";

			File file = new File(path);
			String str;
			int num = 0;
			
			int imgCount = file.listFiles().length;	// 파일 총 갯수 얻어오기
			map = new Bitmap[imgCount];
				
			if ( file.listFiles().length > 0 )
				for ( File f : file.listFiles() ) {
					str = f.getName();				// 파일 이름 얻어오기
					map[num] = BitmapFactory.decodeFile(path+"/"+str);
					num++;
				}
		}
		FileInputStream fis = new FileInputStream(loadPath); // loadPath는 txt파일의 경로
		BufferedReader bufferReader = new BufferedReader(new InputStreamReader(fis));
				
		String str, str1="";
		String map[];

		while( (str = bufferReader.readLine()) != null )	// str에 txt파일의 한 라인을 읽어온다
			str1 += str;									// 읽어온 라인을 str1에 추가한다

		map = str1.split(",");								// 콤마(,)를 기준으로 map String 배열에 추가

		// 만약 0, 100, 123, 111, 122, 5 라면 map={0,100,123,111,122,5}

+ Recent posts