package com.andengine.blackdog.chapter5;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.Vector;

import org.andengine.engine.camera.SmoothCamera;
import org.andengine.engine.camera.hud.HUD;
import org.andengine.engine.camera.hud.controls.DigitalOnScreenControl;
import org.andengine.engine.handler.IUpdateHandler;
import org.andengine.engine.handler.timer.ITimerCallback;
import org.andengine.engine.handler.timer.TimerHandler;
import org.andengine.engine.options.EngineOptions;
import org.andengine.engine.options.ScreenOrientation;
import org.andengine.engine.options.resolutionpolicy.FillResolutionPolicy;
import org.andengine.entity.IEntity;
import org.andengine.entity.modifier.ScaleModifier;
import org.andengine.entity.primitive.Rectangle;
import org.andengine.entity.scene.Scene;
import org.andengine.entity.shape.IShape;
import org.andengine.entity.sprite.AnimatedSprite;
import org.andengine.entity.sprite.Sprite;
import org.andengine.entity.text.Text;
import org.andengine.entity.util.FPSLogger;
import org.andengine.extension.physics.box2d.PhysicsConnector;
import org.andengine.extension.physics.box2d.PhysicsFactory;
import org.andengine.extension.physics.box2d.PhysicsWorld;
import org.andengine.extension.tmx.TMXLayer;
import org.andengine.extension.tmx.TMXLoader;
import org.andengine.extension.tmx.TMXLoader.ITMXTilePropertiesListener;
import org.andengine.extension.tmx.TMXObject;
import org.andengine.extension.tmx.TMXObjectGroup;
import org.andengine.extension.tmx.TMXProperties;
import org.andengine.extension.tmx.TMXTile;
import org.andengine.extension.tmx.TMXTileProperty;
import org.andengine.extension.tmx.TMXTiledMap;
import org.andengine.extension.tmx.util.exception.TMXLoadException;
import org.andengine.input.touch.TouchEvent;
import org.andengine.opengl.font.Font;
import org.andengine.opengl.font.FontFactory;
import org.andengine.opengl.texture.TextureOptions;
import org.andengine.opengl.texture.atlas.bitmap.BitmapTextureAtlas;
import org.andengine.opengl.texture.atlas.bitmap.BitmapTextureAtlasTextureRegionFactory;
import org.andengine.opengl.texture.region.TextureRegion;
import org.andengine.opengl.texture.region.TiledTextureRegion;
import org.andengine.ui.activity.SimpleBaseGameActivity;
import org.andengine.util.debug.Debug;
import org.apache.http.HttpEntity;
import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.ResponseHandler;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.BasicResponseHandler;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.protocol.HTTP;

import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.SharedPreferences;
import android.graphics.Color;
import android.hardware.SensorManager;

import com.andengine.blackdog.R;
import com.andengine.blackdog.chapter5.helper.BaseHelper;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.physics.box2d.Body;
import com.badlogic.gdx.physics.box2d.BodyDef.BodyType;
import com.badlogic.gdx.physics.box2d.Contact;
import com.badlogic.gdx.physics.box2d.ContactImpulse;
import com.badlogic.gdx.physics.box2d.ContactListener;
import com.badlogic.gdx.physics.box2d.FixtureDef;
import com.badlogic.gdx.physics.box2d.Manifold;

public class NinjaRun extends SimpleBaseGameActivity {
	private SmoothCamera camera;

	private static final int CAMERA_WIDTH = 800;
	private static final int CAMERA_HEIGHT = 480;

	public Scene mScene;
	private TMXTiledMap mTMXTiledMap;

	private BitmapTextureAtlas mBitmapTextureAtlas;

	public TiledTextureRegion mPlayer_MPTextureRegion;
	private TiledTextureRegion mPlayerTextureRegion;

	// 적 선언
	private TiledTextureRegion mEnemyTextureRegion;
	// 총알 선언
	private TiledTextureRegion mShurikenTextureRegion;

	// 검기 선언
	private TiledTextureRegion mSwordTextureRegion;

	public PhysicsWorld mPhysicsWorld;

	private static int mapOffset = 100;

	// --------------------------------
	// FixtureDefs 생성을 위한 Category bits
	// --------------------------------
	private static final short CATEGORYBIT_WALL = 1;
	private static final short CATEGORYBIT_PLAYER = 2;
	private static final short CATEGORYBIT_ENEMY = 4;
	private static final short CATEGORYBIT_SHURIKEN = 8;
	// static으로 선언할 돈은 벽과 같은 categorybit으로 선언합니다.
	// 이 값이 매우 중요한데 엉뚱한 9, 16 등등의 값을 셋팅하면 플레이어의 벽, 돈과의 충돌이 제대로 이루어 지지 않습니다.
	private static final short CATEGORYBIT_MONEY = 1;
	private static final short CATEGORYBIT_TRAP = 1;
	private static final short CATEGORYBIT_TREASURE = 1;

	// --------------------------------
	// FixtureDefs 생성을 위한 Mask bits
	// --------------------------------
	private static final short MASKBITS_WALL = CATEGORYBIT_WALL
			+ CATEGORYBIT_PLAYER + CATEGORYBIT_ENEMY + CATEGORYBIT_SHURIKEN;

	private static final short MASKBITS_PLAYER = CATEGORYBIT_WALL
			+ CATEGORYBIT_PLAYER + CATEGORYBIT_ENEMY;

	private static final short MASKBITS_ENEMY = CATEGORYBIT_WALL
			+ CATEGORYBIT_SHURIKEN + CATEGORYBIT_ENEMY + CATEGORYBIT_PLAYER;

	private static final short MASKBITS_SHURIKEN = CATEGORYBIT_WALL
			+ CATEGORYBIT_ENEMY;

	// 돈은 캐릭터와 부딪힐때 소멸됩니다.
	// 정상적으로 선언한다면
	// MASKBITS_MONEY = CATEGORYBIT_MONEY + CATEGORYBIT_PLAYER
	// +CATEGORYBIT_WALL;
	// 이 될 것 같지만 이렇게 하면 캐릭터와 돈이 부딪힐때 제대로 돈이 없어지지 않습니다.
	// 벽과 돈을 같은 카테고리로 선언했기 때문에 MASKBITS_MONEY = CATEGORYBIT_MONEY +
	// CATEGORYBIT_PLAYER 가
	// 성립됩니다.
	private static final short MASKBITS_MONEY = CATEGORYBIT_MONEY
			+ CATEGORYBIT_PLAYER;

	private static final short MASKBITS_TRAP = CATEGORYBIT_TRAP
			+ CATEGORYBIT_PLAYER;

	private static final short MASKBITS_TREASURE = CATEGORYBIT_TREASURE
			+ CATEGORYBIT_PLAYER;

	public ArrayList<IEntity> mEntityList;
	private static AnimatedSprite player_sprite;
	private static Body player_body;
	private FixtureDef boxFixtureDef;
	private Rectangle rect;

	// 컨트롤러 선언
	private DigitalOnScreenControl mDigitalOnScreenControl;
	private TextureRegion mOnScreenControlBaseTextureRegion;
	private TextureRegion mOnScreenControlKnobTextureRegion;

	private BitmapTextureAtlas mOnScreenControlTexture;
	private BitmapTextureAtlas mHUDTextureAtlas;

	// 컨트롤러에 따른 플레이어 캐릭터의 방향 지정
	private static float mLinearVelocityX = 8.0f;
	public boolean isPlayerMoving = false;

	// 점프에 대한 셋팅
	private TextureRegion mJumpTextureRegion;
	public HUD mHUD;
	private boolean isLanded = false;
	private boolean firstJump = false;
	private boolean secondJump = false;

	public static float mImpulseY = 10f;
	private String fix1_name = "", fix2_name = "";

	// --------------------------------------
	// 표창의 추가에 따른 변수 선언
	// --------------------------------------
	// 플레이어의 방향 값 설정
	public static final short PLAYER_TO_RIGHT = 1;
	public static final short PLAYER_TO_LEFT = -1;
	private int shurikenCount = 0;
	private boolean shurikenPresent = false;
	private TextureRegion mShootTextureRegion;
	public int playerDir = 1;
	private boolean desShuriken = false; // 표창의 메모리 해제를 위해
	private boolean doShuriken = false; // 표창을 던지고 있는 중인가 체크
	public Integer shurikenLeft = 20; // 초기에 제공할 표창 갯수 100개면 충분히 깸

	// --------------------------------------
	// 적 출현에 대한 선언
	// --------------------------------------
	public int enemyCount = 0;
	boolean[] enemyLandedArr;
	public int remainingEnemies;
	private boolean desEnemy = false;
	private boolean enemyLanded = false;

	// --------------------------------------
	// 에너지바에 대한 설정
	// --------------------------------------
	private boolean reduceHealth = false;
	private AnimatedSprite mHealthSprite;
	private TiledTextureRegion mHealthTextureRegion;
	private float refrainImpulse = 5.0f;
	private float Player_Max_Health = 100.0f; // 전체 게이지
	private float Player_Health_Reduce = 10.0f; // 한번 부딪히면 깍이는 게이지

	// --------------------------------------
	// 돈 선언
	// --------------------------------------
	private TiledTextureRegion mMoneyTextureRegion;
	public int moneyCount = 0;
	private boolean desMoney = false;
	private boolean moneyLanded = false;

	// --------------------------------------
	// 돈틀 텍스트로 표기
	// 돈과 거리 관련 선언
	// --------------------------------------
	Text leftText; // 돈
	Text centerText; // 거리
	Text rightText; // 표창수
	private Font mFont;
	long startTime = 0;
	// counting
	long calcuTime = 0;
	int finalCount = 0; // 최종달린수
	long waitTime = 0;
	String calcuTimeString = "0";
	String moneyString = "0";
	Integer dollarCount = 0;

	// 튜닝
	boolean jumping = false; // 점프하게 되면 true

	TimerHandler timerHandler = null;
	String objectName;

	// 함정
	private boolean desTrap = false;

	// 보물
	private boolean desTreasure = false;

	// 칼 선언
	AnimatedSprite mAnimated;
	AnimatedSprite mNowEnemy;
	SharedPreferences pref = null;

	@Override
	public EngineOptions onCreateEngineOptions() {
		// float pMaxVelocityX, float pMaxVelocityY 는 chaseEntity를 설정할 때,
		// 카메라가 따라가는 속도를 의미합니다.
		// 값이 클수록 카메라가 빠르게 캐릭터를 따라 붙습니다.
		this.camera = new SmoothCamera(0, 0, CAMERA_WIDTH, CAMERA_HEIGHT, 1000,
				1000, 1.0f);

		EngineOptions engineOptions = new EngineOptions(true,
				ScreenOrientation.LANDSCAPE_FIXED, new FillResolutionPolicy(),
				camera);

		return engineOptions;
	}

	@Override
	protected void onCreateResources() {
		BitmapTextureAtlasTextureRegionFactory.setAssetBasePath("gfx/");

		// --------------------------------------------------------------------
		// 글자의 Font 선언
		// --------------------------------------------------------------------

		FontFactory.setAssetBasePath("font/");

		this.mFont = FontFactory.createFromAsset(this.getFontManager(),
				this.getTextureManager(), 512, 512, TextureOptions.BILINEAR,
				this.getAssets(), "Plok.ttf", 28, true, Color.WHITE);
		this.mFont.load();

		startTime = System.currentTimeMillis();

		// 닌자, 적, 표창 이미지 호출
		loadImages();

		// 컨트롤러 이미지 호출
		loadControllers();
	}

	// ---------------------------------------------------------
	// DigitalOnScreenControl 추가
	// ---------------------------------------------------------
	public void callController() {

		// HUD란 모니터 화면, 게임 화면을 의미합니다.
		// HUD에 붙여야 카메라가 이동해도 항상 화면의 일정한 곳에 텍스트 점수, 버튼이 고정됩니다.
		mHUD = new HUD();

		// ------------------------------------------------------
		// 점프 버튼을 생성하고 HUD에 붙입니다.
		// ------------------------------------------------------
		Sprite jump = new Sprite(CAMERA_WIDTH - 140, CAMERA_HEIGHT - 175,
				mJumpTextureRegion, this.getVertexBufferObjectManager()) {

			@Override
			public boolean onAreaTouched(TouchEvent pEvent, float pX, float pY) {

				// 점프 버튼이 클릭되고, 플레이어 캐릭이 땅에 도착했을 때 점프한다.
				if (pEvent.isActionDown() && (isLanded || firstJump)) {

					jumpPlayer(player_body);

					isLanded = false;

				}
				if (pEvent.isActionUp()) {

					isLanded = false;
				}
				return false;

			}

		};
		jump.setScale(0.70f);
		mHUD.registerTouchArea(jump);
		mHUD.attachChild(jump);

		// ------------------------------------------------------
		// 표창을 던지는 버튼을 생성하고 HUD에 붙입니다.
		// ------------------------------------------------------
		Sprite shoot = new Sprite(CAMERA_WIDTH - 765, CAMERA_HEIGHT - 175,
				mShootTextureRegion, this.getVertexBufferObjectManager()) {
			@Override
			public boolean onAreaTouched(TouchEvent pEvent, float pX, float pY) {

				if (pEvent.isActionDown()) {

					if (!doShuriken) {
						// 표창을 던지되 플레이어가 바라보고 있는 방향으로 쏘아야 합니다.
						// 그래서 playerDir이 필요합니다.
						if (shurikenLeft != 0) {
							showShuriken(player_sprite, playerDir, "shuriken");
							shurikenLeft--;
						}
						// 표창이 없으면 칼만 휘두릅니다.
						else {
							showSword(player_sprite, playerDir);
						}
					}
					doShuriken = true;
				}

				if (pEvent.isActionUp()) {
					doShuriken = false;
				}
				return false;
			}
		};
		shoot.setScale(0.60f);
		mHUD.registerTouchArea(shoot);
		mHUD.attachChild(shoot);

		// -------------------------------------------------------------------------
		// 에너지바 스프라이트를 생성하고 HUM에 붙입니다.
		// -------------------------------------------------------------------------
		mHealthSprite = new AnimatedSprite(CAMERA_WIDTH - 256, 10,
				mHealthTextureRegion, this.getVertexBufferObjectManager());

		mHealthSprite.setScale(0.5f);
		mHUD.attachChild(mHealthSprite);

		// ----------------------------------------------------------------------
		// text 돈 dollar 표기
		// ----------------------------------------------------------------------
		leftText = new Text(80, 35, this.mFont, "0 Dollar",
				"XXXX Dollar".length(), this.getVertexBufferObjectManager());
		leftText.registerEntityModifier(new ScaleModifier(2, 0.0f, 1.0f));
		mHUD.attachChild(leftText);

		// ----------------------------------------------------------------------
		// text 거리표기
		// ----------------------------------------------------------------------
		centerText = new Text(350, 35, this.mFont, "0 Meter",
				"XXXX Meter".length(), this.getVertexBufferObjectManager());
		centerText.registerEntityModifier(new ScaleModifier(2, 0.0f, 1.0f));
		mHUD.attachChild(centerText);

		// ----------------------------------------------------------------------
		// text 남은 표창수 표기
		// ----------------------------------------------------------------------
		rightText = new Text(700, 80, this.mFont, "0", "XXXX".length(),
				this.getVertexBufferObjectManager());
		rightText.registerEntityModifier(new ScaleModifier(2, 0.0f, 1.0f));
		mHUD.attachChild(rightText);

		// mCamera에 mHUD를 붙여야 캐릭터가 화면을 벗어나 이동을 해도 버튼이 그대로 머물게 됩니다.
		// 그리고 이 라인이 있어야 점프 버튼이 보입니다.
		camera.setHUD(mHUD);

		// ----------------------------------------------------------------------
		// 컨트롤러 셋팅
		// ----------------------------------------------------------------------
		// this.mDigitalOnScreenControl = new DigitalOnScreenControl(10,
		// CAMERA_HEIGHT
		// - this.mOnScreenControlBaseTextureRegion.getHeight()
		// - 5, this.camera,
		// this.mOnScreenControlBaseTextureRegion,
		// this.mOnScreenControlKnobTextureRegion, 0.1f,
		// this.getVertexBufferObjectManager(),
		// new IOnScreenControlListener() {
		//
		// @Override
		// public void onControlChange(
		// final BaseOnScreenControl pBaseOnScreenControl,
		// final float pValueX, final float pValueY) {
		//
		// // 컨트롤러 우측 방향 && 캐릭터가 뛰고 있지 않을 때
		// if (pValueX > 0 && !player_sprite.isAnimationRunning()) {
		// movePlayerRight(player_sprite, player_body);
		// }
		//
		// // 컨트롤러 좌측 방향 && 캐릭터가 뛰고 있지 않을 때
		// else if (pValueX < 0
		// && !player_sprite.isAnimationRunning()) {
		// movePlayerLeft(player_sprite, player_body);
		// }
		//
		// // 컨트롤러가 중앙에 있고, 플레이어가 움직이고 있다면 플레이어를 멈춘다.
		// else if (pValueX == 0) {
		// if (isPlayerMoving) {
		// stopPlayer(player_sprite, player_body);
		// isPlayerMoving = false;
		// }
		// }
		// }
		// });
		//
		// this.mDigitalOnScreenControl.getControlBase().setBlendFunction(
		// GL10.GL_SRC_ALPHA, GL10.GL_ONE_MINUS_SRC_ALPHA);
		// this.mDigitalOnScreenControl.getControlBase().setAlpha(0.55f);
		// this.mDigitalOnScreenControl.getControlBase().setScaleCenter(0, 128);
		// this.mDigitalOnScreenControl.getControlBase().setScale(1.5f);
		// this.mDigitalOnScreenControl.getControlKnob().setAlpha(0.40f);
		// this.mDigitalOnScreenControl.getControlKnob().setScale(0.7f);
		// this.mDigitalOnScreenControl.refreshControlKnobPosition();
		// this.mDigitalOnScreenControl.setAllowDiagonal(false);

	}

	/**
	 * 
	 * 칼을 휘두르고 일정 시간 딜레이 후, 잔상이 사라지도록 합니다.
	 * 
	 * @param mSwordSprite
	 */
	public void destroySword(AnimatedSprite mSwordSprite) {
		mAnimated = mSwordSprite;
		timerHandler = new TimerHandler((float) 0.1f, new ITimerCallback() {
			@Override
			public void onTimePassed(final TimerHandler pTimerHandler) {
				mScene.detachChild(mAnimated);
				mAnimated = null;

			}
		});
		this.getEngine().registerUpdateHandler(timerHandler);

	}

	/**
	 * 
	 * 검의 잔상이 나타나도록 합니다.
	 * 
	 * @param _playerSprite
	 * @param _playerDir
	 */
	public void showSword(AnimatedSprite _playerSprite, int _playerDir) {

		AnimatedSprite mSwordSprite = new AnimatedSprite(_playerSprite.getX()
				+ _playerDir + 80, _playerSprite.getY(), mSwordTextureRegion,
				this.getVertexBufferObjectManager());
		mScene.attachChild(mSwordSprite);
		// 칼을 휘두르고 잔상은 약간의 delay후 사라짐
		destroySword(mSwordSprite);
	}

	/***********************************************************
	 * 
	 * 표창이 나타나게 하고, UserData에 이름을 셋팅합니다.
	 * 
	 ***********************************************************/

	public void showShuriken(AnimatedSprite _playerSprite, int _playerDir,
			String shurikenName) {
		// 메모리 해제에 사용되므로 표창의 갯수 카운팅은 매우 중요합니다.
		shurikenCount++;

		AnimatedSprite mShurikenSprite = new AnimatedSprite(
				_playerSprite.getX() + _playerDir, _playerSprite.getY()
						+ _playerSprite.getHeight() / 4,
				mShurikenTextureRegion, this.getVertexBufferObjectManager());

		FixtureDef mShurikenFixtureDef = PhysicsFactory.createFixtureDef(0, 0f,
				0f, false, CATEGORYBIT_SHURIKEN, MASKBITS_SHURIKEN, (short) 0);

		Body mShurikenBody = PhysicsFactory.createCircleBody(
				this.mPhysicsWorld, mShurikenSprite, BodyType.DynamicBody,
				mShurikenFixtureDef);
		mShurikenBody.setUserData(shurikenName + shurikenCount);

		// AndEngine에는 Body에 총알 같은 움직임을 적용하는 setBullet()이라는 함수가 별도로 존재합니다.
		mShurikenBody.setBullet(true);

		this.mPhysicsWorld.registerPhysicsConnector(new PhysicsConnector(
				mShurikenSprite, mShurikenBody, true, true));
		mShurikenSprite.setUserData(shurikenName + shurikenCount);
		mShurikenBody.setLinearVelocity(_playerDir * 20, 0);

		mScene.attachChild(mShurikenSprite);

		shurikenPresent = true;
		mEntityList.add(mShurikenSprite);

		destroyShuriken(mShurikenSprite);
	}

	/**
	 * 
	 * 던진 표창이 1초후 사라지게 한다.
	 * 
	 * @param mSwordSprite
	 */
	public void destroyShuriken(AnimatedSprite mShuriken) {
		mAnimated = mShuriken;
		timerHandler = new TimerHandler((float) 2.0f, new ITimerCallback() {
			@Override
			public void onTimePassed(final TimerHandler pTimerHandler) {
				mScene.detachChild(mAnimated);
				mAnimated = null;

			}
		});
		this.getEngine().registerUpdateHandler(timerHandler);

	}

	/*********************************************************
	 * 
	 * mImpulseY 값 만큼 점프합니다.
	 * 
	 *********************************************************/

	public void jumpPlayer(Body _playerBody) {

		_playerBody.applyLinearImpulse(0, -mImpulseY, 0,
				_playerBody.getPosition().y);

	}

	/*********************************************************
	 * 
	 * 컨트롤러 동작에 따른 플레이어 캐릭터 우측으로 움직이기
	 * 
	 *********************************************************/

	public void movePlayerRight(AnimatedSprite _playerSprite, Body _playerBody) {
		_playerBody.setLinearVelocity(mLinearVelocityX,
				_playerBody.getLinearVelocity().y);
		// 4컷자리 이미지
		_playerSprite.animate(new long[] { 50, 50, 50, 50 }, 0, 3, false);

		if (_playerSprite.getUserData().toString().contains("player")) {
			isPlayerMoving = true;
			playerDir = PLAYER_TO_RIGHT;
		}

	}

	/*********************************************************
	 * 
	 * 컨트롤러 동작에 따른 플레이어 캐릭터 좌측으로 움직이기
	 * 
	 *********************************************************/

	public void movePlayerLeft(AnimatedSprite _playerSprite, Body _playerBody) {

		_playerBody.setLinearVelocity(-mLinearVelocityX,
				_playerBody.getLinearVelocity().y);

		_playerSprite.animate(new long[] { 50, 50, 50, 50 }, 0, 3, false);

		if (_playerSprite.getUserData().toString().contains("player")) {
			isPlayerMoving = true;
			playerDir = PLAYER_TO_LEFT;
		}
	}

	/*********************************************************
	 * 
	 * 컨트롤러 동작에 따른 플레이어 캐릭터 멈추기
	 * 
	 *********************************************************/

	public void stopPlayer(AnimatedSprite _playerSprite, Body _playerBody) {
		_playerBody.setLinearVelocity(0f, _playerBody.getLinearVelocity().y);
	}

	/*********************************************************
	 * 
	 * 컨트롤러 구성을 위한 이미지를 추가합니다.
	 * 
	 *********************************************************/

	private void loadControllers() {

		// create atlas of 512*1024
		this.mHUDTextureAtlas = new BitmapTextureAtlas(
				this.getTextureManager(), 512, 1024,
				TextureOptions.BILINEAR_PREMULTIPLYALPHA);

		// 점프 버튼 이미지 로드
		this.mJumpTextureRegion = BitmapTextureAtlasTextureRegionFactory
				.createFromAsset(this.mHUDTextureAtlas, this, "jump.png", 0,
						128);

		// 표창 던지기 버튼 이미지 로드
		this.mShootTextureRegion = BitmapTextureAtlasTextureRegionFactory
				.createFromAsset(mHUDTextureAtlas, this, "shoot_shuriken.png",
						128, 0);

		this.mEngine.getTextureManager().loadTexture(this.mHUDTextureAtlas);

		// -------------------------------------------
		// 생명 게이지 바
		// -------------------------------------------

		this.mHealthTextureRegion = BitmapTextureAtlasTextureRegionFactory
				.createTiledFromAsset(this.mHUDTextureAtlas, this,
						"health.png", 0, 256, 1, 11);

		// create atlas of 256*128
		this.mOnScreenControlTexture = new BitmapTextureAtlas(
				this.getTextureManager(), 256, 128,
				TextureOptions.BILINEAR_PREMULTIPLYALPHA);

		// 컨트롤러 이미지를 atlas에 추가
		this.mOnScreenControlBaseTextureRegion = BitmapTextureAtlasTextureRegionFactory
				.createFromAsset(this.mOnScreenControlTexture, this,
						"onscreen_control_base.png", 0, 0);

		this.mOnScreenControlKnobTextureRegion = BitmapTextureAtlasTextureRegionFactory
				.createFromAsset(this.mOnScreenControlTexture, this,
						"onscreen_control_knob.png", 128, 0);

		// 디지털 컨트롤의 이미지 출력
		this.mEngine.getTextureManager().loadTexture(
				this.mOnScreenControlTexture);
	}

	private void loadImages() {

		// create atlas of 512*512
		this.mBitmapTextureAtlas = new BitmapTextureAtlas(
				this.getTextureManager(), 1024, 1025, TextureOptions.BILINEAR);

		// 플레이어 캐릭터
		this.mPlayerTextureRegion = BitmapTextureAtlasTextureRegionFactory
				.createTiledFromAsset(this.mBitmapTextureAtlas, this,
						"ninja.gif", 0, 0, 4, 1);

		// 적 캐릭터
		// 적캐릭터 경우는 그냥 원하는대로 만들어서 넣으면 됩니다.
		this.mEnemyTextureRegion = BitmapTextureAtlasTextureRegionFactory
				.createTiledFromAsset(this.mBitmapTextureAtlas, this,
						"enemy.gif", 0, 128, 4, 1);

		// 돈 이미지 선언
		this.mMoneyTextureRegion = BitmapTextureAtlasTextureRegionFactory
				.createTiledFromAsset(this.mBitmapTextureAtlas, this,
						"dollar100.png", 512, 512, 1, 1);

		// 표창
		this.mShurikenTextureRegion = BitmapTextureAtlasTextureRegionFactory
				.createTiledFromAsset(this.mBitmapTextureAtlas, this,
						"weapon.gif", 0, 256, 1, 1);

		// 검기 이미지 선언
		this.mSwordTextureRegion = BitmapTextureAtlasTextureRegionFactory
				.createTiledFromAsset(this.mBitmapTextureAtlas, this,
						"attack.gif", 512, 0, 1, 1);

		this.mBitmapTextureAtlas.load();
	}

	/**
	 * 
	 * 동전을 먹을 때, 플레이어 캐릭터가 각종 벽, 적과 부딪히는 처리 속도를 따라오지 못하기 때문에 따로 동전 메모리를 해제하기 위한
	 * 함수를 선언해서 호출합니다.
	 * 
	 * @param name
	 */
	public void callTimerHandler(String name) {
		objectName = name; // 접근하기 위해서는 전역변수에 값 할당이 필요합니다.
		timerHandler = new TimerHandler((float) 0.001f, new ITimerCallback() {
			@Override
			public void onTimePassed(final TimerHandler pTimerHandler) {

				Debug.d("time handler is called" + desMoney);
				// 돈이 캐릭터와 부딪힐때 해당 메모리를 해제합니다.
				if (desMoney) {
					Debug.d("inside time handler is called about money");
					destroyGameObject(objectName);

					desMoney = false;
				}

				// 캐릭터와 함정이 부딪힐때 해당 메모리를 해제합니다.
				if (desTrap) {
					Debug.d("inside time handler is called about trap");
					destroyGameObject(objectName);

					desTrap = false;

					saveScore(calcuTimeString);
					finish();
				}

				// 캐릭터와 보물이 부딪힐때 해당 메모리를 해제합니다.
				if (desTreasure) {
					Debug.d("inside time handler is called about treasure");
					destroyGameObject(objectName);

					desTreasure = false;

					saveScore(calcuTimeString);
					finish();
				}

			}
		});
		this.getEngine().registerUpdateHandler(timerHandler);
	}

	/*************************************************************
	 * 
	 * 충돌에 대한 처리를 합니다.
	 * 
	 *************************************************************/
	private void createCollision() {
		this.mPhysicsWorld.setContactListener(new ContactListener() {

			public void beginContact(Contact contact) {

				// 2개의 바디가 부딪혔을 때 userData를 가져옵니다.
				if (contact.getFixtureA().getBody().getUserData() != null
						&& contact.getFixtureA().getBody().getUserData() != null) {

					fix1_name = contact.getFixtureA().getBody().getUserData()
							.toString();
					fix2_name = contact.getFixtureB().getBody().getUserData()
							.toString();

				} else {
					fix1_name = "";
					fix2_name = "";
				}

				Debug.d("fix1_name : " + fix1_name);
				Debug.d("fix2_name : " + fix2_name);

				// player와 벽속성이 부딪힐때 isLanded를 true로 설정합니다.
				// 이렇게 설정해야 점프 버튼 클릭시 계속해서 높이 떠오르는 것을 막을 수 있습니다.
				if ((fix1_name.contains("player") && fix2_name.contains("wall"))
						|| (fix2_name.contains("player") && fix1_name
								.contains("wall"))) {
					isLanded = true;
					Debug.d("player hits wall");
				}

				// 플레이어가 함정에 빠졌을 때에 대한 처리
				if ((fix1_name.contains("player") && fix2_name.contains("trap"))
						|| (fix2_name.contains("player") && fix1_name
								.contains("trap"))) {
					Debug.d("player hits trap");
					desTrap = true;

					if (contact.getFixtureA().getBody().getUserData()
							.toString().contains("trap")) {
						callTimerHandler(contact.getFixtureA().getBody()
								.getUserData().toString());
					}

					if (contact.getFixtureB().getBody().getUserData()
							.toString().contains("trap")) {
						callTimerHandler(contact.getFixtureB().getBody()
								.getUserData().toString());
					}
				}

				// 플레이어가 보물에 빠졌을 때에 대한 처리
				if ((fix1_name.contains("player") && fix2_name
						.contains("treasure"))
						|| (fix2_name.contains("player") && fix1_name
								.contains("treasure"))) {
					Debug.d("player hits treasure");
					desTreasure = true;

					if (contact.getFixtureA().getBody().getUserData()
							.toString().contains("treasure")) {
						callTimerHandler(contact.getFixtureA().getBody()
								.getUserData().toString());
					}

					if (contact.getFixtureB().getBody().getUserData()
							.toString().contains("treasure")) {
						callTimerHandler(contact.getFixtureB().getBody()
								.getUserData().toString());
					}
				}

				// 플레이어와 돈의 충돌
				// 돈을 없애고, 돈 점수를 올립니다.
				if ((fix1_name.contains("player") && fix2_name
						.contains("money"))
						|| (fix2_name.contains("player") && fix1_name
								.contains("money"))) {
					desMoney = true;
					Debug.d("player hits money");

					// Dollar에 대한 점수를 올립니다.
					dollarCount++;

					if (contact.getFixtureA().getBody().getUserData()
							.toString().contains("money")) {
						callTimerHandler(contact.getFixtureA().getBody()
								.getUserData().toString());
					}

					if (contact.getFixtureB().getBody().getUserData()
							.toString().contains("money")) {
						callTimerHandler(contact.getFixtureB().getBody()
								.getUserData().toString());
					}

				}

				// 표창과 벽의 충돌
				if ((fix1_name.contains("shuriken") && fix2_name
						.equalsIgnoreCase("wall"))
						|| (fix2_name.contains("shuriken") && fix1_name
								.equalsIgnoreCase("wall"))) {

					desShuriken = true;
				}

				// 표창과 적군의 충돌
				if ((fix1_name.contains("shuriken") && fix2_name
						.contains("enemy"))

						|| (fix2_name.contains("shuriken") && fix1_name
								.contains("enemy"))) {
					desEnemy = true;
					desShuriken = true;

				}

				// 플레이어와 적의 충돌시의 처리. 에너지바를 줄일 수 있도록 합니다.
				if ((fix1_name.contains("player") && fix2_name
						.contains("enemy"))
						|| (fix2_name.contains("player") && fix1_name
								.contains("enemy"))) {

					// 칼과 적군의 충돌
					if (fix2_name.contains("enemy")) {
						if (mAnimated != null) {

							IEntity targetEntity = null;
							int i = 0;
							for (IEntity pEntity : mEntityList) {
								if (pEntity.getUserData() != null) {
									if (pEntity.getUserData().toString()
											.equals(fix2_name)) {
										targetEntity = pEntity;
										break;
									}
								}
								i++;
							}

							AnimatedSprite bodySprite = (AnimatedSprite) mEntityList
									.get(i);

							if (mAnimated.collidesWith(bodySprite)) {
								Debug.d("got cha!!B ");
								desEnemy = true;
							} else {
								reduceHealth = true;
							}

						} else {
							reduceHealth = true;
						}
					}
					//
					else if (fix1_name.contains("enemy")) {
						if (mAnimated != null) {
							IEntity targetEntity = null;
							int i = 0;
							for (IEntity pEntity : mEntityList) {
								if (pEntity.getUserData() != null) {
									if (pEntity.getUserData().toString()
											.equals(fix1_name)) {
										targetEntity = pEntity;
										break;
									}
								}
								i++;
							}

							AnimatedSprite bodySprite = (AnimatedSprite) mEntityList
									.get(i);

							if (mAnimated.collidesWith(bodySprite)) {
								Debug.d("got cha!!A ");
								desEnemy = true;
							} else {
								reduceHealth = true;
							}
						} else {
							reduceHealth = true;
						}
					}
					Debug.d("player hits enemy");
					// reduceHealth = true;
					isLanded = true;
				} else
					reduceHealth = false;

			}

			public void endContact(Contact contact) {
			}

			public void preSolve(Contact contact, Manifold oldManifold) {

			}

			public void postSolve(Contact contact, ContactImpulse impulse) {
				if (enemyLanded) {

					for (int i = 0; i < enemyCount; i++) {
						if (fix2_name.equals("enemy" + i)) {
							enemyLandedArr[i] = true;
							Debug.d("enemylanded at " + i + " true");
						}
					}

					enemyLanded = false;
				}
			}

		});

	}

	/*************************************************************
	 * 
	 * 메모리 해제
	 * 
	 *************************************************************/

	public void destroyGameObject(String name) {

		Debug.d(name + "메모리해제");
		if (mPhysicsWorld.getPhysicsConnectorManager().findBodyByShape(
				findShape(name)) != null) {
			Debug.d(name + "메모리해제 inside");
			// 스프라이트를 스크린에서 제거하고 스크린과 관련된 바디를 삭제합니다.
			mScene.detachChild(findShape(name));
			mPhysicsWorld.destroyBody(mPhysicsWorld
					.getPhysicsConnectorManager().findBodyByShape(
							findShape(name)));
			mPhysicsWorld.unregisterPhysicsConnector(mPhysicsWorld
					.getPhysicsConnectorManager().findPhysicsConnectorByShape(
							findShape(name)));
		}

	}

	/**************************************************************
	 * 
	 * 표창이 중력의 영향을 받지 않고 직선으로 날아가도록 합니다.
	 * 
	 **************************************************************/

	private void makeShurikenDefyGravity() {
		for (IEntity pEntity : mEntityList) {
			if (pEntity.getUserData() != null) {
				if (pEntity.getUserData().toString().contains("shuriken")) {

					final Body pShurikenBody = mPhysicsWorld
							.getPhysicsConnectorManager().findBodyByShape(
									(IShape) pEntity);
					if (pShurikenBody != null)
						pShurikenBody.applyForce(new Vector2(0,
								-SensorManager.GRAVITY_EARTH), pShurikenBody
								.getWorldCenter());

				}
			}
		}
	}

	/**********************************************************************************
	 * 
	 * player and enemy, 두 바디 사이의 거리를 측정합니다.
	 * 
	 **********************************************************************************/

	public float getDistance(Body _player, Body _enemy) {
		float dist_x = (float) Math.pow(
				_player.getPosition().x - _enemy.getPosition().x, 2);

		float dist_y = (float) Math.pow(
				_player.getPosition().y - _enemy.getPosition().y, 2);

		// Debug.d(dist_x+" "+dist_y);
		return ((float) Math.sqrt(dist_x + dist_y));
	}

	/**********************************************************************************
	 * 
	 * 플레이어 캐릭터의 움직이는 방향에 따라서 적 캐릭터가 해당 위치로 이동합니다.
	 * 
	 **********************************************************************************/

	public void doAIActions(Body temp_enemy_body, int _playerDir, int action) {
		temp_enemy_body.applyLinearImpulse(0, -5.0f,
				temp_enemy_body.getPosition().x,
				temp_enemy_body.getPosition().y);
		if (_playerDir == PLAYER_TO_RIGHT)
			temp_enemy_body.setLinearVelocity(-mLinearVelocityX,
					temp_enemy_body.getLinearVelocity().y);

		if (_playerDir == PLAYER_TO_LEFT)
			temp_enemy_body.setLinearVelocity(mLinearVelocityX,
					temp_enemy_body.getLinearVelocity().y);

	}

	/**********************************************************************************
	 * 
	 * 적의 바디에 인공지능을 부여합니다.
	 * 
	 **********************************************************************************/

	public void doAICalculations(Body _playerBody) {
		for (int i = 0; i < enemyCount; i++) {
			IShape temp_enemy_shape = findShape("enemy" + i);
			Body temp_enemy_body = mPhysicsWorld.getPhysicsConnectorManager()
					.findBodyByShape(temp_enemy_shape);

			if (temp_enemy_body != null) {

				if (getDistance(_playerBody, temp_enemy_body) < 10.0f
						&& enemyLandedArr[i]) {

					doAIActions(temp_enemy_body, playerDir, 0);

					enemyLandedArr[i] = false;

				}

				else if (enemyLandedArr[i]) {
					temp_enemy_body.setLinearVelocity(0, 0);
				}

			}

		}
	}

	private String sendData(String param1, String param2, String API_URL)
			throws ClientProtocolException, IOException {
		// TODO Auto-generated method stub
		HttpPost request = makeHttpPost(param1, param2, API_URL);
		HttpClient client = new DefaultHttpClient();
		ResponseHandler<String> reshandler = new BasicResponseHandler();
		String result = client.execute(request, reshandler);
		return result;
	}

	// Post 방식일경우
	private HttpPost makeHttpPost(String param1, String param2, String url) {
		// TODO Auto-generated method stub
		HttpPost post = new HttpPost(url);
		Vector<NameValuePair> params = new Vector<NameValuePair>();
		String param = param2 + "_" + param1;

		params.add(new BasicNameValuePair("my_meter", param));
		// params.add(new BasicNameValuePair("score", param2));
		post.setEntity(makeEntity(params));
		return post;
	}

	private HttpEntity makeEntity(Vector<NameValuePair> params) {
		HttpEntity result = null;
		try {
			result = new UrlEncodedFormEntity(params, HTTP.UTF_8);
		} catch (UnsupportedEncodingException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return result;
	}

	// 프로그램을 종료하시겠습니까?
	void setDialog() {
		AlertDialog.Builder builder = new AlertDialog.Builder(this);
		builder.setIcon(R.drawable.icon)
				.setTitle("NinjaRun")
				// .setMessage("메인으로 돌아 가시겠습니까? 도중에 중단하면 기록이 저장되지 않습니다.")
				.setMessage("return to menu? score won't be recored.")
				.setCancelable(false)
				.setPositiveButton("예", new DialogInterface.OnClickListener() {
					public void onClick(DialogInterface dialog, int id) {
						finish();
					}
				})
				.setNegativeButton("아니오",
						new DialogInterface.OnClickListener() {
							public void onClick(DialogInterface dialog, int id) {
							}
						});
		builder.create().show();
	}

	public void back() {
		setDialog();
	}

	@Override
	public void onBackPressed() {
		// TODO Auto-generated method stub
		this.back();
	}

	/**
	 * 최종 점수를 저장합니다.
	 * 
	 * @param count
	 */
	public void saveScore(String count) {
		SharedPreferences pref = getSharedPreferences("pref",
				Activity.MODE_PRIVATE);
		SharedPreferences.Editor editor = pref.edit();
		editor.putString("score", count.toString());

		// ---------------------------------------------
		// money
		// ---------------------------------------------
		String beforeMoney = pref.getString("money", "");
		Integer beforeMoneyInt = 0;
		if (beforeMoney != "") {
			beforeMoneyInt = Integer.parseInt(beforeMoney);
		}
		Integer moneyStringInt = Integer.parseInt(moneyString);
		moneyStringInt = beforeMoneyInt + moneyStringInt;
		moneyString = moneyStringInt.toString();
		editor.putString("money", moneyString);

		// 표창
		editor.putString("shuriken", shurikenLeft.toString());

		editor.commit(); // 저장합니다.

		// 이름 입력하기
		String name = pref.getString("editText", "");
		String url = BaseHelper.URL + "rank_name.php";

		try {
			String result = sendData(name.toString(), count.toString(), url);
		} catch (ClientProtocolException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	/**********************************************************************************
	 * 
	 * 에너지바를 업데이트 합니다.
	 * 
	 **********************************************************************************/

	private void updateHealthBar() {

		if (reduceHealth && mHealthSprite != null && player_body != null) {

			player_body.applyLinearImpulse((float) (refrainImpulse * 1.5),
					-refrainImpulse, player_body.getPosition().x,
					player_body.getPosition().y);

			Player_Max_Health -= Player_Health_Reduce;

			switch ((int) Player_Max_Health) {
			case 100:
				break;
			case 90:
				mHealthSprite.animate(new long[] { 50, 50 }, 0, 1, false);
				break;
			case 80:
				mHealthSprite.animate(new long[] { 50, 50 }, 1, 2, false);
				break;
			case 70:
				mHealthSprite.animate(new long[] { 50, 50 }, 2, 3, false);
				break;
			case 60:
				mHealthSprite.animate(new long[] { 50, 50 }, 3, 4, false);
				break;
			case 50:
				mHealthSprite.animate(new long[] { 50, 50 }, 4, 5, false);
				break;
			case 40:
				mHealthSprite.animate(new long[] { 50, 50 }, 5, 6, false);
				break;
			case 30:
				mHealthSprite.animate(new long[] { 50, 50 }, 6, 7, false);
				break;
			case 20:
				mHealthSprite.animate(new long[] { 50, 50 }, 7, 8, false);
				break;
			case 10:
				mHealthSprite.animate(new long[] { 50, 50 }, 8, 9, false);
				break;
			case 0:
				mHealthSprite.animate(new long[] { 50, 50 }, 9, 10, false);
				saveScore(calcuTimeString);
				finish();

				break;

			default:
				break;

			}

			// 생명이 0이면 플레이어가 죽도록 합니다.

			reduceHealth = false;
		}
	}

	public void showMoney() {
		moneyString = Integer.toString(dollarCount);
		leftText.setText(moneyString + " Dollar");
	}

	public void showShuriken() {
		String shurikenString = Integer.toString(shurikenLeft);
		rightText.setText(shurikenString);
	}

	public void showMeter() {
		long nowTime = System.currentTimeMillis(); // 현재시간
		calcuTime = calcuTime - waitTime;
		calcuTime = nowTime - startTime;
		calcuTime = calcuTime / 1000;

		calcuTime = (calcuTime - waitTime) * 10;

		// 시간 표기
		calcuTimeString = Long.toString(calcuTime);
		centerText.setText(calcuTimeString + " Meter");
	}

	public void createUpdateHandler() {

		this.mScene.registerUpdateHandler(new IUpdateHandler() {

			public void onUpdate(float pSecondsElapsed) {

				// 달린거리를 표기합니다.
				showMeter();

				// 돈이 표기됩니다.
				showMoney();

				// 표창의 남은 갯수를 표기합니다.
				showShuriken();

				// 표창이 중력의 영향을 받지 않고 직선으로 날아가도록 합니다.
				// runner 게임에서는 오히려 중력이 작용하는게 이쁜것 같습니다.
				makeShurikenDefyGravity();

				// runner 게임에서는 적 캐릭의 ai를 제거해볼께요~
				doAICalculations(player_body);

				// destroyGameObject 부분을 잘 선언하여야 미사일을 쏜 후, 미사일이 정상적으로 사라지게 됩니다.
				if (desShuriken) {

					if (fix1_name.contains("shuriken"))
						destroyGameObject(fix1_name);

					if (fix2_name.contains("shuriken"))
						destroyGameObject(fix2_name);

					desShuriken = false;
				}

				// 적이 표창에 맞았을 때 해당 메모리를 해제합니다.
				if (desEnemy) {

					if (fix1_name.contains("enemy"))
						destroyGameObject(fix1_name);

					if (fix2_name.contains("enemy"))
						destroyGameObject(fix2_name);

					desEnemy = false;
				}

				updateHealthBar();

				// 충돌을 빠르게 감지해 나갈때 동전이 제대로 해제되지 않는 현상이 발경되어
				// TimerHandler로 따로 구현해보았습니다.

				// 러너 게임을 위한 효과입니다.
				// 쭉~ 오른쪽으로 가라~
				player_body.setLinearVelocity(7f,
						player_body.getLinearVelocity().y);

			}

			@Override
			public void reset() {

			}

		});

	}

	@Override
	protected Scene onCreateScene() {
		this.mEngine.registerUpdateHandler(new FPSLogger());

		mScene = new Scene();

		try {
			final TMXLoader tmxLoader = new TMXLoader(this.getAssets(),
					this.mEngine.getTextureManager(),
					TextureOptions.BILINEAR_PREMULTIPLYALPHA,
					this.getVertexBufferObjectManager(),
					new ITMXTilePropertiesListener() {
						@Override
						public void onTMXTileWithPropertiesCreated(
								final TMXTiledMap pTMXTiledMap,
								final TMXLayer pTMXLayer,
								final TMXTile pTMXTile,
								final TMXProperties<TMXTileProperty> pTMXTileProperties) {
						}
					});

			// 타일맵 로드
			this.mTMXTiledMap = tmxLoader.loadFromAsset("tmx/map_black.tmx");

		} catch (final TMXLoadException e) {
			Debug.e(e);
		}

		final TMXLayer tmxLayer = this.mTMXTiledMap.getTMXLayers().get(0);
		mScene.attachChild(tmxLayer);

		this.mPhysicsWorld = new PhysicsWorld(new Vector2(0,
				SensorManager.GRAVITY_EARTH), false);
		mScene.registerUpdateHandler(this.mPhysicsWorld);

		// EntityList 생성하는 부분을 loadObjectsFromMap 위쪽으로 올려 주세요.
		mEntityList = new ArrayList<IEntity>(mScene.getChildCount());

		for (int i = 0; i < mScene.getChildCount(); i++)
			mEntityList.add(mScene.getChildByIndex(i));

		// 벽과 적군에 대한 타일맵 로드
		loadObject(mTMXTiledMap);

		// 표창 초기 갯수 셋팅
		pref = getSharedPreferences("pref", Activity.MODE_PRIVATE);
		String shurikenString = pref.getString("shuriken", "");
		if (shurikenString != null && shurikenString.length()!=0) {
			shurikenLeft = Integer.parseInt(shurikenString);
		}
		// 충돌에 대한 처리를 합니다.
		createCollision();

		// AndEngine의 Handler 처리를 합니다.
		createUpdateHandler();

		// 컨트롤러 동작 호출
		callController();

		// 러너 게임에서는 컨트롤러를 없애는 것이 좋을 듯 합니다.
		// mScene.setChildScene(this.mDigitalOnScreenControl);

		// 플레이어 캐릭터를 "player"라는 이름으로 등장시킨다.
		showPlayer("player", mPlayerTextureRegion);

		// 플레이어 캐릭터의 스프라이트와 바디 선언
		player_sprite = (AnimatedSprite) findShape("player");
		player_body = mPhysicsWorld.getPhysicsConnectorManager()
				.findBodyByShape(player_sprite);

		// 적캐릭터를 로드하고, 배열에 할당합니다.
		// 적캐릭터에 인공지능을 부여하기 위해 필요합니다.
		enemyLandedArr = new boolean[enemyCount];

		for (int i = 0; i < enemyCount; i++) {
			enemyLandedArr[i] = true;
		}
		remainingEnemies = enemyCount;

		// 이 부분을 설정해야 타일맵에서 좌우 여백이 제대로 셋팅됩니다.
		this.camera.setBoundsEnabled(true);
		this.camera.setBounds(0, 0, tmxLayer.getWidth(), tmxLayer.getHeight());

		// 맵에서 카메라 따라오기
		camera.setChaseEntity(player_sprite);

		return mScene;
	}

	/**********************************************************************************
	 * 
	 * 파라미터로 받은 xLoc, yLoc에 적캐릭터가 등장하도록 합니다. UserData에는 ["enemy"+적갯수]가 저장됩니다.
	 * 
	 **********************************************************************************/

	public void showMoney(int xLoc, int yLoc) {

		AnimatedSprite mMoneySprite = new AnimatedSprite(xLoc, yLoc,
				mMoneyTextureRegion, this.getVertexBufferObjectManager());
		mMoneySprite.setScale(0.5f);

		FixtureDef mMoneyFixtureDef = PhysicsFactory.createFixtureDef(0, 0f,
				0f, false, CATEGORYBIT_MONEY, MASKBITS_MONEY, (short) 0);

		Body mMoneyBody = PhysicsFactory.createCircleBody(this.mPhysicsWorld,
				mMoneySprite, BodyType.StaticBody, mMoneyFixtureDef);

		mMoneyBody.setUserData("money" + moneyCount);

		this.mPhysicsWorld.registerPhysicsConnector(new PhysicsConnector(
				mMoneySprite, mMoneyBody, true, true));
		mMoneySprite.setUserData("money" + moneyCount);
		moneyCount++;

		mScene.attachChild(mMoneySprite);
		mEntityList.add(mMoneySprite);
	}

	/**********************************************************************************
	 * 
	 * 파라미터로 받은 xLoc, yLoc에 적캐릭터가 등장하도록 합니다. UserData에는 ["enemy"+적갯수]가 저장됩니다.
	 * 
	 **********************************************************************************/

	public void showEnemy(int xLoc, int yLoc) {

		AnimatedSprite mEnemySprite = new AnimatedSprite(xLoc, yLoc,
				mEnemyTextureRegion, this.getVertexBufferObjectManager());
		mEnemySprite.setScale(1.3f);

		FixtureDef mEnemyFixtureDef = PhysicsFactory.createFixtureDef(0, 0f,
				0f, false, CATEGORYBIT_ENEMY, MASKBITS_ENEMY, (short) 0);

		Body mEnemyBody = PhysicsFactory.createBoxBody(this.mPhysicsWorld,
				mEnemySprite, BodyType.DynamicBody, mEnemyFixtureDef);
		mEnemyBody.setUserData("enemy" + enemyCount);

		this.mPhysicsWorld.registerPhysicsConnector(new PhysicsConnector(
				mEnemySprite, mEnemyBody, true, true));
		mEnemySprite.setUserData("enemy" + enemyCount);
		enemyCount++;

		mScene.attachChild(mEnemySprite);
		mEnemySprite.animate(100);

		mEnemySprite.setCullingEnabled(true);

		mNowEnemy = mEnemySprite;
		mEntityList.add(mEnemySprite);
	}

	/*****************************************************
	 * 
	 * 플레이어 캐릭터 등장
	 * 
	 *****************************************************/

	public void showPlayer(String playerName, TiledTextureRegion playerTexture) {

		AnimatedSprite mPlayerSprite = new AnimatedSprite(mapOffset, 0,
				playerTexture, this.getVertexBufferObjectManager());
		mPlayerSprite.setScale(1.3f);

		final FixtureDef mPlayerFixtureDef = PhysicsFactory.createFixtureDef(0,
				0f, 0f, false, CATEGORYBIT_PLAYER, MASKBITS_PLAYER, (short) 0);

		Body mPlayerBody = PhysicsFactory.createBoxBody(this.mPhysicsWorld,
				mPlayerSprite, BodyType.DynamicBody, mPlayerFixtureDef);
		mPlayerSprite.setUserData(playerName);
		mPlayerBody.setUserData(playerName);
		this.mPhysicsWorld.registerPhysicsConnector(new PhysicsConnector(
				mPlayerSprite, mPlayerBody, true, false));

		mScene.attachChild(mPlayerSprite);

		// 숫자가 작을 수록 애니메이션의 속도가 빨라집니다.
		mPlayerSprite.animate(500);
		mEntityList.add(mPlayerSprite);
	}

	/***********************************************************
	 * 
	 * UserData string (name)에 해당하는 모양을 찾는 함수 입니다.
	 * 
	 ***********************************************************/

	public IShape findShape(String shapeName) {
		IShape pShape = null;

		// 존재하는 모든 entities들을 체크하면서
		// UserData 문자열에 해당하는 값이 있는 entity를 리턴합니다.
		for (IEntity pEntity : mEntityList) {
			if (pEntity.getUserData() != null) {
				if (pEntity.getUserData().toString()
						.equalsIgnoreCase(shapeName)) {
					pShape = (IShape) pEntity;
				}
			}
		}
		return pShape;
	}

	/************************************************************
	 * 
	 * tmx map에 사각 영역을 선언해두고, 이 영역에 적이 나타나게 됩니다.
	 * 
	 ************************************************************/
	private void loadEnemiesFromObjects(TMXObjectGroup _group) {

		// tmx group에서 모든 Object들을 탐색함
		for (final TMXObject object : _group.getTMXObjects()) {

			// 적 캐릭터를 등장시킴
			showEnemy(object.getX(), object.getY());
		}
	}

	private void loadWallFromObjects(TMXObjectGroup _group, String _userData) {

		for (final TMXObject object : _group.getTMXObjects()) {

			// tmx map에 사각형을 생성합니다.
			rect = new Rectangle(object.getX(), object.getY(),
					object.getWidth(), object.getHeight(),
					this.getVertexBufferObjectManager());

			// 벽에 해당하는 FixtureDef를 생성합니다.
			boxFixtureDef = PhysicsFactory.createFixtureDef(0, 0, 1f, false,
					CATEGORYBIT_WALL, MASKBITS_WALL, (short) 0);

			// 벽을 StaticBody로 선언하고 userData에 셋팅합니다.
			PhysicsFactory.createBoxBody(this.mPhysicsWorld, rect,
					BodyType.StaticBody, boxFixtureDef).setUserData(_userData);

			// 사각형 영역을 보이지 않게 만듭니다.
			rect.setVisible(false);

			mScene.attachChild(rect);

			mEntityList.add(rect);
		}
	}

	/**
	 * 
	 * 함정에 빠졌을 때에 대한 처리
	 * 
	 * @param _group
	 * @param _userData
	 */
	private void loadTrapFromObjects(TMXObjectGroup _group, String _userData) {

		for (final TMXObject object : _group.getTMXObjects()) {

			// tmx map에 사각형을 생성합니다.
			rect = new Rectangle(object.getX(), object.getY(),
					object.getWidth(), object.getHeight(),
					this.getVertexBufferObjectManager());

			// trap에 해당하는 FixtureDef를 생성합니다.
			boxFixtureDef = PhysicsFactory.createFixtureDef(0, 0, 1f, false,
					CATEGORYBIT_TRAP, MASKBITS_TRAP, (short) 0);

			// trap을 StaticBody로 선언하고 userData에 셋팅합니다.
			PhysicsFactory.createBoxBody(this.mPhysicsWorld, rect,
					BodyType.StaticBody, boxFixtureDef).setUserData(_userData);

			// 사각형 영역을 보이지 않게 만듭니다.
			rect.setVisible(false);

			mScene.attachChild(rect);

			mEntityList.add(rect);
		}
	}

	/**
	 * 
	 * 보물의 빠졌 로드 대한 처리
	 * 
	 * @param _group
	 * @param _userData
	 */
	private void loadTreasureFromObjects(TMXObjectGroup _group, String _userData) {

		for (final TMXObject object : _group.getTMXObjects()) {

			// tmx map에 사각형을 생성합니다.
			rect = new Rectangle(object.getX(), object.getY(),
					object.getWidth(), object.getHeight(),
					this.getVertexBufferObjectManager());

			// treasure에 해당하는 FixtureDef를 생성합니다.
			boxFixtureDef = PhysicsFactory.createFixtureDef(0, 0, 1f, false,
					CATEGORYBIT_TREASURE, MASKBITS_TREASURE, (short) 0);

			// treasure을 StaticBody로 선언하고 userData에 셋팅합니다.
			PhysicsFactory.createBoxBody(this.mPhysicsWorld, rect,
					BodyType.StaticBody, boxFixtureDef).setUserData(_userData);

			// 사각형 영역을 보이지 않게 만듭니다.
			rect.setVisible(false);

			mScene.attachChild(rect);

			mEntityList.add(rect);
		}
	}

	/************************************************************
	 * 
	 * tmx map에 사각 영역을 선언해두고, 이 영역에 돈이 나타나게 됩니다.
	 * 
	 ************************************************************/
	private void loadMoneyFromObjects(TMXObjectGroup _group) {

		// tmx group에서 모든 Object들을 탐색함
		for (final TMXObject object : _group.getTMXObjects()) {

			// 돈을 등장시킴
			showMoney(object.getX(), object.getY());
		}
	}

	/**
	 * 
	 * 벽, 적, 돈과 같은 오브젝트를 맵에서 로드합니다.
	 * 
	 * @param map
	 */
	private void loadObject(TMXTiledMap map) {

		// tmx map에서 모든 object groups을 가져와서 속성 이름을 체크합니다.

		for (final TMXObjectGroup group : map.getTMXObjectGroups()) {

			if (group.getName().equals("wall")) {
				loadWallFromObjects(group, "wall");
			}

			// 돈 로드
			if (group.getName().equals("money")) {
				loadMoneyFromObjects(group);
			}

			// 타일맵상에 속성을 enemies라고 표기하면 게임 시작시 해당 위치에 자동으로 enemies가 나타납니다.
			if (group.getName().equals("enemies")) {
				loadEnemiesFromObjects(group);
			}

			// 함정 추가시
			if (group.getName().equals("trap")) {
				loadTrapFromObjects(group, "trap");
			}

			// 보물 추가시
			if (group.getName().equals("treasure")) {
				loadTrapFromObjects(group, "treasure");
			}
		}

	}

}
