基于cocos2d开发的android小游戏——採花仙

/*cocos 2d 已经成为了如今移动端游戏开发的强有力的工具,眼下主流游戏中多採用cocos 2d游戏引擎。

我也尝试了一下该引擎。我是用的是cocos2d-android,以后要移植到Cocos2d-x上。废话不多说,代码例如以下。*/基于cocos2d开发的android小游戏——採花仙

package com.ilighti.flowerfairy;

import com.tencent.stat.StatService;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Random;
import java.util.Timer;
import java.util.TimerTask;

import org.apache.http.util.EncodingUtils;
import org.cocos2d.actions.CCScheduler;
import org.cocos2d.actions.base.CCRepeatForever;
import org.cocos2d.actions.instant.CCHide;
import org.cocos2d.actions.instant.CCShow;
import org.cocos2d.actions.interval.CCAnimate;
import org.cocos2d.actions.interval.CCBlink;
import org.cocos2d.actions.interval.CCIntervalAction;
import org.cocos2d.actions.interval.CCScaleTo;
import org.cocos2d.layers.CCLayer;
import org.cocos2d.layers.CCMultiplexLayer;
import org.cocos2d.layers.CCScene;
import org.cocos2d.menus.CCMenu;
import org.cocos2d.menus.CCMenuItem;
import org.cocos2d.menus.CCMenuItemImage;
import org.cocos2d.nodes.CCAnimation;
import org.cocos2d.nodes.CCDirector;
import org.cocos2d.nodes.CCLabel;
import org.cocos2d.nodes.CCSprite;
import org.cocos2d.nodes.CCSpriteFrame;
import org.cocos2d.nodes.CCSpriteSheet;
import org.cocos2d.nodes.CCTextureCache;
import org.cocos2d.opengl.CCGLSurfaceView;
import org.cocos2d.sound.SoundEngine;

import org.cocos2d.types.CGPoint;
import org.cocos2d.types.CGRect;
import org.cocos2d.types.CGSize;
import org.cocos2d.types.ccColor3B;

//import com.badlogic.gdx.math.Vector2;
//import com.badlogic.gdx.physics.box2d.Body;
//import com.badlogic.gdx.physics.box2d.BodyDef;
//import com.badlogic.gdx.physics.box2d.EdgeShape;
//import com.badlogic.gdx.physics.box2d.World;
import com.ilighti.flowerfairy.R.raw;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup.LayoutParams;
import android.view.Window;
import android.view.WindowManager;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;

import com.qq.e.ads.AdRequest;
import com.qq.e.ads.AdSize;
import com.qq.e.ads.AdView;
import com.ilighti.flowerfairy.Constants;

/**
 * An example full-screen activity that shows and hides the system UI (i.e.
 * status bar and navigation/system bar) with user interaction.
 * 
 * @see SystemUiHider
 */
public class FlowerMainActivity extends Activity {
	private AdView bannerAD;
	private LinearLayout bannerContainer;
	/**
	 * CoCos2d surface view
	 */
	private CCGLSurfaceView surfaceView = null;
	private CCScene scene = null;
	public static FlowerMainActivity app;
	private CCMultiplexLayer mlayer = null;
	// private int[] levelSpirit = { 0, 500, 3000, 100000 };
	// private int levelNum = 4;
	private String msg = new String("Level Failed. ");
	private static int idScene = 0;
	private LauncherMenuLayer launcherMenuLayer = null;
	private BirdFlyLayer birdFlyLayer = null;
	private FairyFlyLayer fairyFlyLayer = null;
	private GirlFlyLayer girlFlyLayer = null;
	private GameOverLayer gameOverLayer = null;
	private FinalLayer finalLayer = null;
	private GameState gameState = new GameState();

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		StatService.trackCustomEvent(this, "onCreate", "");
		app = this;
		requestWindowFeature(Window.FEATURE_NO_TITLE);
		getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
				WindowManager.LayoutParams.FLAG_FULLSCREEN);
		getWindow().setFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON,
				WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);

		this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);

		readState();
		refineState();

		surfaceView = new CCGLSurfaceView(this); // create surface view

		CCDirector director = CCDirector.sharedDirector(); // get director
		director.attachInView(surfaceView); // set application view
		director.setDeviceOrientation(CCDirector.kCCDeviceOrientationLandscapeLeft);

		setContentView(surfaceView);

		if (gameState.getStartUpNum() > Constants.freshUserThreshold
				&& gameState.getStartUpToday() < Constants.frequentPlayerThreshold) {
			setupAds();
		}

		director.setDisplayFPS(false); // set display fps or not
		director.setAnimationInterval(1 / 30.0);

		scene = CCScene.node();
		// StartMenuLayer startMenuLayer = new StartMenuLayer();
		// scene.addChild(startMenuLayer);
		// GirlFlyLayer GirlFlyLayer = new GirlFlyLayer();
		// scene.addChild(GirlFlyLayer);

		launcherMenuLayer = new LauncherMenuLayer();
		birdFlyLayer = new BirdFlyLayer();
		fairyFlyLayer = new FairyFlyLayer();
		girlFlyLayer = new GirlFlyLayer();
		gameOverLayer = new GameOverLayer();
		finalLayer = new FinalLayer();

		mlayer = CCMultiplexLayer.node(launcherMenuLayer, birdFlyLayer,
				fairyFlyLayer, girlFlyLayer, gameOverLayer, finalLayer);
		scene.addChild(mlayer, 0);

		SoundEngine.sharedEngine().preloadSound(app, raw.ground);
		SoundEngine.sharedEngine().preloadEffect(this, raw.upgrade);
		SoundEngine.sharedEngine().preloadEffect(this, raw.eat);
		SoundEngine.sharedEngine().preloadEffect(this, raw.die);
		SoundEngine.sharedEngine().preloadEffect(this, raw.fly);
		director.runWithScene(scene);

	}

	private void setupAds() {
		this.bannerContainer = new LinearLayout(this);
		bannerContainer.setOrientation(LinearLayout.HORIZONTAL);
		addContentView(this.bannerContainer, new LayoutParams(
				LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));

		FlowerMainActivity.this.showBannerAD();
	}

	private void showBannerAD() {
		this.bannerAD = new AdView(this, AdSize.BANNER, Constants.APPId,
				Constants.BannerPosId);
		this.bannerContainer.removeAllViews();
		this.bannerContainer.addView(bannerAD);
		bannerAD.fetchAd(new AdRequest());
	}

	private void switchScene(int n) {
		mlayer.switchTo(n);
		idScene = n;
	}

	@Override
	public void onStart() {
		super.onStart();
	}

	@Override
	public void onPause() {
		super.onPause();
		SoundEngine.sharedEngine().pauseSound();
		CCDirector.sharedDirector().onPause();
	}

	@Override
	public void onResume() {
		super.onResume();
		// this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
		// CCDirector.sharedDirector().runWithScene(scene);
		SoundEngine.sharedEngine().resumeSound();
		CCDirector.sharedDirector().onResume();
	}

	@Override
	public void onDestroy() {
		super.onDestroy();

		CCDirector.sharedDirector().end();
		// CCTextureCache.sharedTextureCache().removeAllTextures();
	}

	public void gameOver(String msg) {
		SoundEngine.sharedEngine().playEffect(app, raw.die);
		this.msg = msg;
		app.switchScene(4);
	}

	public String getMsg() {
		return msg;
	}

	public void setMsg(String msg) {
		this.msg = msg;
	}

	public void readState() {
		boolean sdCardExist = Environment.getExternalStorageState().equals(
				android.os.Environment.MEDIA_MOUNTED); // 推断sd卡是否存在
		if (sdCardExist) {
			String fileName = Environment.getExternalStorageDirectory()
					.getPath() + Constants.stateFile;
			File file = new File(fileName);
			if (!file.exists()) {
				String dir = Constants.workDir;
				makeStorageDir(dir);
				writeSDFile(fileName, gameState.toString());
			} else {
				gameState = GameState.parseFromString(readSDFile(fileName));
			}
		}
	}

	public void refineState() {
		gameState.setStartUpNum(gameState.getStartUpNum() + 1);
		SimpleDateFormat sDateFormat = new SimpleDateFormat("yyyy-MM-dd");
		String date = sDateFormat.format(new java.util.Date());
		if (gameState.getSaveDate().equals(date)) {
			gameState.setStartUpToday(gameState.getStartUpToday() + 1);
			if (gameState.getStartUpToday() > gameState.getMaxStartUpOneDay()) {
				gameState.setMaxStartUpOneDay(gameState.getStartUpToday());
			}
		} else {
			gameState.setStartUpToday(0);
			gameState.setSaveDate(date);
		}
		saveState();
	}

	public void saveState() {
		boolean sdCardExist = Environment.getExternalStorageState().equals(
				android.os.Environment.MEDIA_MOUNTED); // 推断sd卡是否存在
		if (sdCardExist) {
			String fileName = Environment.getExternalStorageDirectory()
					.getPath() + Constants.stateFile;
			File file = new File(fileName);
			if (!file.exists()) {
				String dir = Constants.workDir;
				makeStorageDir(dir);
				writeSDFile(fileName, gameState.toString());
			} else {
				writeSDFile(fileName, gameState.toString());
			}
		}
	}

	public boolean makeStorageDir(String dirName) {
		boolean sdCardExist = Environment.getExternalStorageState().equals(
				android.os.Environment.MEDIA_MOUNTED); // 推断sd卡是否存在
		if (sdCardExist) {
			File dir = Environment.getExternalStorageDirectory();
			String path = dir.getPath() + "/" + dirName;
			File dstdir = new File(path);
			dstdir.mkdir();
			return true;
		}
		return false;
	}

	// 读文件
	public String readSDFile(String fileName) {
		String res = null;
		try {
			File file = new File(fileName);
			FileInputStream fis = new FileInputStream(file);
			int length = fis.available();
			byte[] buffer = new byte[length];
			fis.read(buffer);
			res = EncodingUtils.getString(buffer, "UTF-8");
			fis.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return res;
	}

	// 写文件
	public void writeSDFile(String fileName, String write_str) {
		try {
			File file = new File(fileName);
			FileOutputStream fos = new FileOutputStream(file);
			byte[] bytes = write_str.getBytes();
			fos.write(bytes);
			fos.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	static class BirdFlyLayer extends CCLayer {

		private CCSprite[] bird_wave = new CCSprite[3];
		private CCSprite bg = null;
		private int cur = 0;
		private int total = 4;
		private int[] ids = { 0, 1, 2, 1 };

		private CGPoint curPos = null;

		private float speed = 0f;
		private float accel_speed = -10f;
		private float interval_time = 1 / 30.0f;
		private float fly_speed_delta = 35f;
		private int pixels_per_meter = 5;
		private boolean is_started = false;
		private CGSize winSize = null;

		private String[] birds_pics = { "bird_XXlarge.png",
				"wave1_XXlarge.png", "wave2_XXlarge.png" };
		private String[] flower_pics = { "small_flower_a.png",
				"small_flower_b.png", "small_flower_c.png",
				"small_flower_d.png", "small_flower_e.png",
				"small_flower_f.png", "small_flower_g.png",
				"small_flower_h.png", "small_flower_i.png",
				"small_flower_j.png", "small_flower_k.png" };

		private int[] flowerSpirit = { 20, 10, 20, 10, 50, 5, 30, 20, 15, 25, 5 };
		private int flowerCatagory = 11;
		private FlowerProperty[] flowerProperties = null;

		private int spirit = 0;
		private int power = 100;
		private int miss = 0;
		private int spiritThreshold = Constants.levelSpirit[1];
		private int missThreshold = 1;
		private int flyCost = 1;
		private CCLabel labelSpirit = null;
		private CCLabel labelPower = null;
		private String spiritStr = "Spirit";
		private String powerStr = "Power";
		private CGPoint spiritPos = CGPoint.ccp(10, 60);
		private CGPoint powerPos = CGPoint.ccp(10, 85);
		private float widthStep = 0f;

		// private int maxShow = 4;
		private CGPoint flowerSpeed = CGPoint.ccp(-100f, 0f);
		private float flower_interval = 1.5f;
		private Random rand = new Random(System.currentTimeMillis());
		// private List<CCSprite> flowerBuf = new LinkedList<CCSprite>();
		// private List<FlowerState> flowerState = new
		// LinkedList<FlowerState>();
		// protected static final float PTM_RATIO = 32.0f;
		// protected final World bxWorld;

		private CGPoint exRay = CGPoint.ccp(45, 18);
		private float radius = 60f;

		// private CCBlink blink = CCBlink.action(0.2f, 5);
		public BirdFlyLayer() {

			this.setIsTouchEnabled(true);
			winSize = CCDirector.sharedDirector().winSize();
			flowerSpeed = CGPoint.ccp(-252, 0f);

			labelPower = CCLabel.makeLabel(powerStr + ":" + power, "DroidSans",
					32);
			this.addChild(labelPower, 1);
			labelPower.setAnchorPoint(0f, 0f);
			powerPos = CGPoint.ccp(winSize.width / 2f, 40);
			labelPower.setPosition(powerPos);
			labelPower.setColor(ccColor3B.ccBLACK);
			widthStep = labelPower.getContentSize().width + 20f;

			labelSpirit = CCLabel.makeLabel(spiritStr + ":" + spirit,
					"DroidSans", 32);
			this.addChild(labelSpirit, 1);
			labelSpirit.setAnchorPoint(0f, 0f);
			spiritPos = CGPoint.ccp(winSize.width / 2f + widthStep, 40);
			labelSpirit.setPosition(spiritPos);
			labelSpirit.setColor(ccColor3B.ccBLACK);

			CGPoint pnt = CGPoint.ccp(winSize.width / 4, winSize.height / 2);
			curPos = pnt;
			bird_wave[0] = CCSprite.sprite(birds_pics[0]);
			bird_wave[1] = CCSprite.sprite(birds_pics[1]);
			bird_wave[2] = CCSprite.sprite(birds_pics[2]);
			bird_wave[0].setPosition(pnt);
			bird_wave[1].setPosition(pnt);
			bird_wave[2].setPosition(pnt);
			bg = CCSprite.sprite("background.jpg");
			bg.setAnchorPoint(0f, 0f);
			bg.setPosition(CGPoint.ccp(0f, 0f));
			this.addChild(bg);
			this.addChild(bird_wave[0]);
			this.addChild(bird_wave[1]);
			this.addChild(bird_wave[2]);

			bird_wave[1].runAction(CCHide.action());
			bird_wave[2].runAction(CCHide.action());

			flowerProperties = new FlowerProperty[flowerCatagory];
			for (int i = 0; i < flowerCatagory; i++) {
				flowerProperties[i] = new FlowerProperty();
				flowerProperties[i].setImgName(flower_pics[i]);
				CCSprite sprite = CCSprite.sprite(flower_pics[i]);
				sprite.setPosition(CGPoint.ccp(winSize.width,
						winSize.height / 2));
				flowerProperties[i].setFlowerSprite(sprite);
				flowerProperties[i].setFlowerState(new FlowerState(0));
				flowerProperties[i].setSpirit(flowerSpirit[i]);
				flowerProperties[i].setRadius((int) radius);
				flowerProperties[i].setEatable(true);
				this.addChild(sprite);
				sprite.runAction(CCHide.action());
			}
		}

		@Override
		public boolean ccTouchesBegan(MotionEvent event) {
			// TODO Auto-generated method stub
			SoundEngine.sharedEngine().playEffect(app, raw.fly);
			flyUp();
			if (!is_started) {
				this.schedule("nextPosition", interval_time);
				this.schedule("updateFlower");
				this.schedule("startFlower", flower_interval);
				is_started = true;
			}
			return super.ccTouchesBegan(event);
		}

		public void clean() {
			// stop schedule task
			this.unschedule("nextPosition");
			this.unschedule("updateFlower");
			this.unschedule("startFlower");
			// reset start flag
			is_started = false;
			// reset the miss number
			miss = 0;
			// reset speed
			speed = 0;
			// reset the bird state
			CGPoint pnt = CGPoint.ccp(winSize.width / 4, winSize.height / 2);
			curPos = pnt;
			bird_wave[0].setPosition(curPos);
			bird_wave[1].setPosition(curPos);
			bird_wave[2].setPosition(curPos);
			bird_wave[0].runAction(CCShow.action());
			bird_wave[1].runAction(CCHide.action());
			bird_wave[2].runAction(CCHide.action());
			// reset the flowers
			// Iterator<CCSprite> spriteIter = flowerBuf.iterator();
			// Iterator<FlowerState> stateIter = flowerState.iterator();
			// if(scaleSpriteId!=-1) {
			// flowerProperties[scaleSpriteId].getFlowerSprite().stopAction(scaleTo);
			// scaleSpriteId = -1;
			// }
			for (int i = 0; i < flowerCatagory; i++) {
				flowerProperties[i].getFlowerSprite()
						.runAction(CCHide.action());
				flowerProperties[i].getFlowerState().state = 0;
			}
			// reset power and spirit
			power = 100;
			spirit = 0;
			labelPower.setString(powerStr + ":" + power);
			labelSpirit.setString(spiritStr + ":" + spirit);
		}

		@Override
		public boolean ccTouchesEnded(MotionEvent event) {
			// TODO Auto-generated method stub
			flyUp();
			return super.ccTouchesEnded(event);
		}

		@Override
		public boolean ccTouchesMoved(MotionEvent event) {
			// TODO Auto-generated method stub
			return super.ccTouchesMoved(event);
		}

		@Override
		public void onEnter() {
			super.onEnter();

			SoundEngine.sharedEngine().playSound(app, raw.ground, true);
		}

		@Override
		public void onExit() {
			super.onExit();
			SoundEngine.sharedEngine().pauseSound();
		}

		public void nextPosition(float delta) {
			CGPoint flyDeltaVec = CGPoint.ccp(0, speed * interval_time
					* pixels_per_meter);
			CGPoint dstPnt = CGPoint.ccpAdd(curPos, flyDeltaVec);
			curPos = dstPnt;
			bird_wave[0].setPosition(curPos);
			bird_wave[1].setPosition(curPos);
			bird_wave[2].setPosition(curPos);
			CCShow show = CCShow.action();
			bird_wave[ids[cur]].runAction(show);
			speed += accel_speed;
			if (curPos.y <= 0 || curPos.y >= winSize.height) {
				clean();
				if (curPos.y <= 0) {
					app.gameOver("You fell on the ground and died. ");
				} else {
					app.gameOver("You can not fly that high. ");
				}
			}
		}

		public void updateFlower(float delta) {

			for (int i = 0; i < flowerCatagory; i++) {
				FlowerState state = flowerProperties[i].getFlowerState();
				CCSprite sprite = flowerProperties[i].getFlowerSprite();
				if (state.equals(1)) {
					CGPoint pos = sprite.getPosition();
					pos = CGPoint.ccpAdd(pos,
							CGPoint.ccpMult(flowerSpeed, delta));
					if (pos.x <= 0) {
						// scaleSpriteId = i;
						// sprite.runAction(blink);
						// this.unschedule("nextPosition");
						// this.unschedule("updateFlower");
						// this.unschedule("startFlower");
						// Timer mtimer = new Timer();
						// long delay = 200;
						// mtimer.schedule(new TimerTask() {
						// @Override
						// public void run() {
						miss++;
						clean();
						app.gameOver("You have wasted too much opportunities. ");
						// }
						// }, delay);
						break;
					} else if (birdGetFlower(pos, flowerProperties[i])) {
						state.state = 0;
						sprite.setPosition(CGPoint.ccp(winSize.width,
								winSize.height / 2));
						sprite.runAction(CCHide.action());
						birdEatFlower(flowerProperties[i]);
					} else {
						sprite.setPosition(pos);
						CCShow show = CCShow.action();
						sprite.runAction(show);
					}
				}
			}
		}

		private void birdEatFlower(FlowerProperty flowerProperty) {
			// TODO Auto-generated method stub
			SoundEngine.sharedEngine().playEffect(app, raw.eat);
			power += flowerProperty.getSpirit();
			if (power > 100) {
				spirit += power - 100;
				labelSpirit.setString(spiritStr + ":" + spirit);
				if (spirit > spiritThreshold) {
					upgrade();
				}
				power = 100;
			}
			labelPower.setString(powerStr + ":" + power);
		}

		private void upgrade() {
			SoundEngine.sharedEngine().playEffect(app, raw.upgrade);
			clean();
			app.gameState.setGrade(app.gameState.getGrade() + 1);
			app.saveState();
			app.launcherMenuLayer.setGrade(app.gameState.getGrade());
			app.launcherMenuLayer.refreshMenu();
			app.switchScene(2);
		}

		private boolean birdGetFlower(CGPoint pos, FlowerProperty flowerProperty) {
			// TODO Auto-generated method stub
			if (CGPoint.ccpDistance(pos, curPos) < flowerProperty.getRadius()) {
				return true;
			}
			if (CGPoint.ccpDistance(pos, CGPoint.ccpAdd(curPos, exRay)) < flowerProperty
					.getRadius()) {
				return true;
			}
			return false;
		}

		public void startFlower(float delta) {
			int id = Math.abs(rand.nextInt()) % (flowerCatagory);
			int n = 0;
			while (!flowerProperties[id].getFlowerState().equals(0)
					&& n++ < (flowerCatagory)) {
				id = (id + 1) % (flowerCatagory);
			}
			if (n < (flowerCatagory)) {
				CCSprite sprite = flowerProperties[id].getFlowerSprite();
				sprite.setPosition(CGPoint.ccp(winSize.width, winSize.height
						/ 4 + Math.abs(rand.nextInt()) % (winSize.height / 2)));
				sprite.runAction(CCShow.action());
				flowerProperties[id].setFlowerState(new FlowerState(1));
			}
		}

		public void flyUp() {
			CCHide hide = CCHide.action();
			CCShow show = CCShow.action();

			bird_wave[ids[cur]].runAction(hide);
			cur = (++cur) % total;
			bird_wave[ids[cur]].runAction(show);
			speed += fly_speed_delta;
			if (speed < 0) {
				speed = 0;
			}

			power -= flyCost;
			labelPower.setString(powerStr + ":" + power);
		}
	}

	class FairyFlyLayer extends CCLayer {
		private CCSprite[] bird_wave = new CCSprite[2];
		private CCSprite bg = null;
		private int cur = 0;
		private int total = 2;
		private int[] ids = { 0, 1 };

		private CGPoint curPos = null;

		private float speed = 0f;
		private float accel_speed = -10f;
		private float interval_time = 1 / 30.0f;
		private float fly_speed_delta = 35f;
		private int pixels_per_meter = 5;
		private boolean is_started = false;
		CGSize winSize = null;

		private String[] birds_pics = { "small_fairyf.png", "small_fairyw.png" };

		private String[] flower_pics = { "small_flower_a.png",
				"small_flower_b.png", "small_flower_c.png",
				"small_flower_d.png", "small_flower_e.png",
				"small_flower_f.png", "small_flower_g.png",
				"small_flower_h.png", "small_flower_i.png",
				"small_flower_j.png", "small_flower_k.png",
				"small_spirit_killer.png", "small_spirit_killer.png",
				"small_spirit_killer.png", "small_spirit_killer.png" };

		private int[] flowerSpirit = { 20, 10, 20, 10, 50, 5, 30, 20, 15, 25,
				5, -500, -500, -500, -500 };
		private int flowerCatagory = 15;
		private int killerBeginId = 11;
		private FlowerProperty[] flowerProperties = null;

		private int spirit = Constants.levelSpirit[1];
		private int spiritLowThreshold = Constants.levelSpirit[1];
		private int spiritThreshold = Constants.levelSpirit[2];
		private int power = 100;
		// private int miss = 0;
		// private int missThreshold = 3;
		// private int flyCost = 1;
		// private int[] poisonousSpirit = { 500, 500 };
		CCLabel labelSpirit = null;
		CCLabel labelPower = null;

		String spiritStr = "Spirit";
		String powerStr = "Power";
		private CGPoint spiritPos = CGPoint.ccp(10, 60);
		private CGPoint powerPos = CGPoint.ccp(10, 85);
		private float widthStep = 0f;

		// private int totalFlower = 10;
		private CGPoint flowerSpeed = CGPoint.ccp(-100f, 0f);
		private float flower_interval = 1.0f;
		private Random rand = new Random(System.currentTimeMillis());
		// private List<CCSprite> flowerBuf = new LinkedList<CCSprite>();
		// private List<FlowerState> flowerState = new
		// LinkedList<FlowerState>();

		// private CGPoint exRay = CGPoint.ccp(49, 25);
		private CGPoint[] ctrlPoints = { CGPoint.ccp(0f, 75f),
				CGPoint.ccp(37f, 55f), CGPoint.ccp(49, 15),
				CGPoint.ccp(0f, -75f) };
		private CGPoint exRay = ctrlPoints[2];
		private int numCtrlPoints = 4;
		private float radius = 60f;
		private float poisonRadiux = 80f;

		private int eatenFrameNum = 5;
		private int curFrame = 0;
		private String[] eatenPics = { "eatfairy_a.png", "eatfairy_b.png",
				"eatfairy_c.png", "eatfairy_c.png", "eatfairy_c.png"};
		private CCSprite[] eatenFrames = new CCSprite[eatenFrameNum];

		public FairyFlyLayer() {
			winSize = CCDirector.sharedDirector().winSize();
			flowerSpeed = CGPoint.ccp(-winSize.width / 2, 0f);

			this.setIsTouchEnabled(true);
			labelPower = CCLabel.makeLabel(powerStr + ":" + power, "DroidSans",
					32);
			this.addChild(labelPower, 1);
			labelPower.setAnchorPoint(0f, 0f);
			powerPos = CGPoint.ccp(winSize.width / 2f, 40);
			labelPower.setPosition(powerPos);
			labelPower.setColor(ccColor3B.ccBLACK);
			widthStep = labelPower.getContentSize().width + 20f;

			labelSpirit = CCLabel.makeLabel(spiritStr + ":" + spirit,
					"DroidSans", 32);
			this.addChild(labelSpirit, 1);
			labelSpirit.setAnchorPoint(0f, 0f);
			spiritPos = CGPoint.ccp(winSize.width / 2f + widthStep, 40);
			labelSpirit.setPosition(spiritPos);
			labelSpirit.setColor(ccColor3B.ccBLACK);

			CGPoint pnt = CGPoint.ccp(winSize.width / 4, winSize.height / 2);
			curPos = pnt;
			bird_wave[0] = CCSprite.sprite(birds_pics[0]);
			bird_wave[1] = CCSprite.sprite(birds_pics[1]);
			// bird_wave[2] = CCSprite.sprite(birds_pics[2]);
			bird_wave[0].setPosition(pnt);
			bird_wave[1].setPosition(pnt);
			// bird_wave[2].setPosition(pnt);
			bg = CCSprite.sprite("background.jpg");
			bg.setAnchorPoint(0f, 0f);
			bg.setPosition(CGPoint.ccp(0f, 0f));
			this.addChild(bg);
			this.addChild(bird_wave[0]);
			this.addChild(bird_wave[1]);
			// this.addChild(bird_wave[2]);
			bird_wave[1].runAction(CCHide.action());
			// bird_wave[2].runAction(CCHide.action());
			flowerProperties = new FlowerProperty[flowerCatagory];
			for (int i = 0; i < flowerCatagory; i++) {
				flowerProperties[i] = new FlowerProperty();
				flowerProperties[i].setImgName(flower_pics[i]);
				CCSprite sprite = CCSprite.sprite(flower_pics[i]);
				sprite.setPosition(CGPoint.ccp(winSize.width,
						winSize.height / 2));
				flowerProperties[i].setFlowerSprite(sprite);
				flowerProperties[i].setFlowerState(new FlowerState(0));
				flowerProperties[i].setSpirit(flowerSpirit[i]);
				flowerProperties[i].setRadius((int) radius);
				flowerProperties[i].setEatable(true);
				if (i >= killerBeginId) {
					flowerProperties[i].setEatable(false);
					flowerProperties[i].setRadius((int) poisonRadiux);
				}
				this.addChild(sprite);
				sprite.runAction(CCHide.action());
			}

			for (int i = 0; i < eatenFrameNum; i++) {
				eatenFrames[i] = CCSprite.sprite(eatenPics[i]);
				this.addChild(eatenFrames[i]);
				eatenFrames[i].runAction(CCHide.action());
			}
		}

		@Override
		public boolean ccTouchesBegan(MotionEvent event) {
			// TODO Auto-generated method stub
			SoundEngine.sharedEngine().playEffect(app, raw.fly);
			flyUp();
			if (!is_started) {
				this.schedule("nextPosition", interval_time);
				this.schedule("updateFlower");
				this.schedule("startFlower", flower_interval);
				is_started = true;
			}
			return super.ccTouchesBegan(event);
		}

		public void clean() {
			// stop schedule task
			this.unschedule("nextPosition");
			this.unschedule("updateFlower");
			this.unschedule("startFlower");
			this.unschedule("eatFairyAnimation");
			// reset start flag
			is_started = false;
			// reset the miss number
			// miss = 0;
			// reset speed
			speed = 0;
			// reset the bird state
			CGPoint pnt = CGPoint.ccp(winSize.width / 4, winSize.height / 2);
			curPos = pnt;
			bird_wave[0].setPosition(curPos);
			bird_wave[1].setPosition(curPos);
			// bird_wave[2].setPosition(curPos);
			bird_wave[0].runAction(CCShow.action());
			bird_wave[1].runAction(CCHide.action());
			// bird_wave[2].runAction(CCHide.action());
			// reset the flowers
			for (int i = 0; i < flowerCatagory; i++) {
				flowerProperties[i].getFlowerState().state = 0;
				flowerProperties[i].getFlowerSprite()
						.runAction(CCHide.action());
			}
			for (int i = 0; i < eatenFrameNum; i++) {
				eatenFrames[i].runAction(CCHide.action());
			}
			curFrame = 0;
			// reset power and spirit
			power = 100;
			spirit = Constants.levelSpirit[1];
			labelPower.setString(powerStr + ":" + power);
			labelSpirit.setString(spiritStr + ":" + spirit);
		}

		public void eatFairyAnimation(float delta) {
			if (curFrame < eatenFrameNum) {
				eatenFrames[curFrame].setPosition(curPos);
				eatenFrames[curFrame].runAction(CCShow.action());
				if (curFrame > 0) {
					eatenFrames[curFrame - 1].runAction(CCHide.action());
				}
				curFrame++;
			} else {
				clean();
				app.gameOver("You are poisoned to death. ");
			}
		}

		@Override
		public boolean ccTouchesEnded(MotionEvent event) {
			// TODO Auto-generated method stub
			flyUp();
			return super.ccTouchesEnded(event);
		}

		@Override
		public boolean ccTouchesMoved(MotionEvent event) {
			// TODO Auto-generated method stub
			return super.ccTouchesMoved(event);
		}

		@Override
		public void onEnter() {
			super.onEnter();

			SoundEngine.sharedEngine().playSound(app, raw.ground, true);
		}

		@Override
		public void onExit() {
			super.onExit();
			SoundEngine.sharedEngine().pauseSound();
		}

		public void nextPosition(float delta) {
			CGPoint flyDeltaVec = CGPoint.ccp(0, speed * interval_time
					* pixels_per_meter);
			CGPoint dstPnt = CGPoint.ccpAdd(curPos, flyDeltaVec);
			curPos = dstPnt;
			bird_wave[0].setPosition(curPos);
			bird_wave[1].setPosition(curPos);
			// bird_wave[2].setPosition(curPos);
			CCShow show = CCShow.action();
			bird_wave[ids[cur]].runAction(show);
			speed += accel_speed;
			if (curPos.y <= 0 || curPos.y >= winSize.height) {
				clean();
				if (curPos.y <= 0) {
					app.gameOver("You fell on the ground and died. ");
				} else {
					app.gameOver("You are not F22 or J20. ");
				}
			}
		}

		public void updateFlower(float delta) {
			for (int i = 0; i < flowerCatagory; i++) {
				FlowerState state = flowerProperties[i].getFlowerState();
				CCSprite sprite = flowerProperties[i].getFlowerSprite();
				if (state.equals(1)) {
					CGPoint pos = sprite.getPosition();
					pos = CGPoint.ccpAdd(pos,
							CGPoint.ccpMult(flowerSpeed, delta));
					if (pos.x <= 0) {
						state.state = 0;
						sprite.setPosition(CGPoint.ccp(winSize.width,
								winSize.height / 2));
						sprite.runAction(CCHide.action());
					} else if (birdGetFlower(pos, flowerProperties[i])) {
						state.state = 0;
						sprite.setPosition(CGPoint.ccp(winSize.width,
								winSize.height / 2));
						sprite.runAction(CCHide.action());
						birdEatFlower(flowerProperties[i]);
					} else {
						sprite.setPosition(pos);
						CCShow show = CCShow.action();
						sprite.runAction(show);
					}
				}
			}
		}

		private void birdEatFlower(FlowerProperty flowerProperty) {
			// TODO Auto-generated method stub
			SoundEngine.sharedEngine().playEffect(app, raw.eat);
			if (!flowerProperty.isEatable()) {
				//SoundEngine.sharedEngine().playEffect(app, raw.die);
				// spirit += flowerProperty.getSpirit();
				this.unschedule("nextPosition");
				this.unschedule("updateFlower");
				this.unschedule("startFlower");
				this.schedule("eatFairyAnimation", 0.1f);
				/*
				 * Timer mtimer = new Timer(); long delay = 1000;
				 * //this.schedule("cleanGameOver", delay); mtimer.schedule(new
				 * TimerTask() {
				 * 
				 * @Override public void run() { // TODO Auto-generated method
				 * stub clean(); app.gameOver("You are poisoned to death. "); }
				 * }, delay);
				 */
			} else {
				spirit += flowerProperty.getSpirit();
				if (spirit >= spiritThreshold) {
					clean();
					upgrade();
				}
			}
			labelSpirit.setString(spiritStr + ":" + spirit);
		}

		private void upgrade() {
			SoundEngine.sharedEngine().playEffect(app, raw.upgrade);
			clean();
			app.gameState.setGrade(app.gameState.getGrade() + 1);
			app.saveState();
			app.launcherMenuLayer.setGrade(app.gameState.getGrade());
			app.launcherMenuLayer.refreshMenu();
			app.switchScene(3);
		}

		private boolean birdGetFlower(CGPoint pos, FlowerProperty flowerProperty) {
			// TODO Auto-generated method stub
			if (!flowerProperty.isEatable()) {
				if (CGPoint.ccpDistance(pos, curPos) < flowerProperty
						.getRadius()) {
					return true;
				}
				for (int i = 0; i < numCtrlPoints; i++) {
					if (CGPoint.ccpDistance(pos,
							CGPoint.ccpAdd(curPos, ctrlPoints[i])) < flowerProperty
							.getRadius()) {
						return true;
					}
				}
			} else {
				if (CGPoint.ccpDistance(pos, curPos) < flowerProperty
						.getRadius()) {
					return true;
				}
				if (CGPoint.ccpDistance(pos, CGPoint.ccpAdd(curPos, exRay)) < flowerProperty
						.getRadius()) {
					return true;
				}
			}
			return false;
		}

		public void startFlower(float delta) {
			int killerRate = 5;
			int base = 0;
			int isKiller = Math.abs(rand.nextInt()) % killerRate;
			if (isKiller > 0) {
				base = killerBeginId;
			}
			int id = Math.abs(rand.nextInt()) % (flowerCatagory - base) + base;
			int n = 0;
			while (!flowerProperties[id].getFlowerState().equals(0)
					&& n++ < (flowerCatagory)) {
				id = (id + 1) % (flowerCatagory);
			}
			if (n < (flowerCatagory)) {
				CCSprite sprite = flowerProperties[id].getFlowerSprite();
				sprite.setPosition(CGPoint.ccp(winSize.width, winSize.height
						/ 4 + Math.abs(rand.nextInt()) % (winSize.height / 2)));
				sprite.runAction(CCShow.action());
				flowerProperties[id].setFlowerState(new FlowerState(1));
			}
		}

		public void flyUp() {
			CCHide hide = CCHide.action();
			CCShow show = CCShow.action();

			bird_wave[ids[cur]].runAction(hide);
			cur = (++cur) % total;
			bird_wave[ids[cur]].runAction(show);
			speed += fly_speed_delta;
			if (speed < 0) {
				speed = 0;
			}

		}

	}

	class GirlFlyLayer extends CCLayer {
		private CCSprite[] bird_wave = new CCSprite[2];
		private CCSprite bg = null;
		private int cur = 0;
		private int total = 2;
		private int[] ids = { 0, 1 };

		private CGPoint curPos = null;

		private float speed = 0f;
		private float accel_speed = -10f;
		private float interval_time = 1 / 30.0f;
		private float fly_speed_delta = 35f;
		private int pixels_per_meter = 5;
		private boolean is_started = false;
		CGSize winSize = null;

		private String[] birds_pics = { "girlf.png", "girlw.png" };
		private String[] flower_pics = { "little_flower_a.png",
				"little_flower_b.png", "little_flower_c.png",
				"little_flower_d.png" };
		private String[] big_flower_pics = { "flower_a.png", "flower_b.png",
				"flower_c.png", "flower_d.png" };

		private int spirit = Constants.levelSpirit[2];
		private int spiritThreshold = Constants.levelSpirit[3];
		private int power = 100;
		private int miss = 0;
		private int missThreshold = 1;
		// private int flyCost = 1;
		private int[] flowerSpirit = { 20, 10, 20, 10 };
		// private int[] poisonousSpirit = { 100, 200 };
		CCLabel labelSpirit = null;
		CCLabel labelPower = null;

		String spiritStr = "Spirit";
		String powerStr = "Power";
		private CGPoint spiritPos = CGPoint.ccp(10, 60);
		private CGPoint powerPos = CGPoint.ccp(10, 85);
		private float widthStep = 0f;

		private int flowerCatagory = 4;
		private int totalFlower = 16;
		private CGPoint flowerSpeed = CGPoint.ccp(-300f, 0f);
		private CGPoint maxFlowerSpeed = null;
		private float flower_interval = 1.5f;
		private Random rand = new Random(System.currentTimeMillis());
		private List<CCSprite> flowerBuf = new LinkedList<CCSprite>();
		private List<CCSprite> bigFlowerBuf = new LinkedList<CCSprite>();
		private List<FlowerState> flowerState = new LinkedList<FlowerState>();
		// protected static final float PTM_RATIO = 32.0f;
		// protected final World bxWorld;

		// private CGPoint exRay = CGPoint.ccp(49, 25);
		private CGPoint[] ctrlPoints = { CGPoint.ccp(0f, 100f),
				CGPoint.ccp(90f, 100f), CGPoint.ccp(90f, 0f),
				CGPoint.ccp(-90f, 0f) };
		// private CGPoint exRay = ctrlPoints[2];
		private int numCtrlPoints = 4;
		private float radiux = 75f;

		// private float poisonRadiux = 75f;

		public GirlFlyLayer() {
			winSize = CCDirector.sharedDirector().winSize();
			flowerSpeed = CGPoint.ccp(-winSize.width / 2, 0f);
			maxFlowerSpeed = CGPoint.ccp(-winSize.width, 0f);

			labelPower = CCLabel.makeLabel(powerStr + ":" + power, "DroidSans",
					32);
			this.addChild(labelPower, 1);
			labelPower.setAnchorPoint(0f, 0f);
			powerPos = CGPoint.ccp(winSize.width / 2f, 40);
			labelPower.setPosition(powerPos);
			labelPower.setColor(ccColor3B.ccBLACK);
			widthStep = labelPower.getContentSize().width + 20f;

			labelSpirit = CCLabel.makeLabel(spiritStr + ":" + spirit,
					"DroidSans", 32);
			this.addChild(labelSpirit, 1);
			labelSpirit.setAnchorPoint(0f, 0f);
			spiritPos = CGPoint.ccp(winSize.width / 2f + widthStep, 40);
			labelSpirit.setPosition(spiritPos);
			labelSpirit.setColor(ccColor3B.ccBLACK);

			// bird_wave[2].setPosition(pnt);
			bg = CCSprite.sprite("background.jpg");
			bg.setAnchorPoint(0f, 0f);
			bg.setPosition(CGPoint.ccp(0f, 0f));
			this.addChild(bg);

			for (int j = 0; j < totalFlower; j++) {
				int k = j % flowerCatagory;
				CCSprite sprite = CCSprite.sprite(flower_pics[k]);
				CCSprite bigSprite = CCSprite.sprite(big_flower_pics[k]);
				sprite.setPosition(CGPoint.ccp(winSize.width,
						winSize.height / 2));
				bigSprite.setPosition(CGPoint.ccp(winSize.width,
						winSize.height / 2));
				flowerBuf.add(sprite);
				bigFlowerBuf.add(bigSprite);
				flowerState.add(new FlowerState(0));
				this.addChild(sprite);
				this.addChild(bigSprite);
				sprite.runAction(CCHide.action());
				bigSprite.runAction(CCHide.action());
			}

			CGPoint pnt = CGPoint.ccp(winSize.width / 4, winSize.height / 2);
			curPos = pnt;
			bird_wave[0] = CCSprite.sprite(birds_pics[0]);
			bird_wave[1] = CCSprite.sprite(birds_pics[1]);
			// bird_wave[2] = CCSprite.sprite(birds_pics[2]);
			bird_wave[0].setPosition(pnt);
			bird_wave[1].setPosition(pnt);
			this.addChild(bird_wave[0]);
			this.addChild(bird_wave[1]);

			bird_wave[1].runAction(CCHide.action());
			this.setIsTouchEnabled(true);
		}

		@Override
		public boolean ccTouchesBegan(MotionEvent event) {
			// TODO Auto-generated method stub
			SoundEngine.sharedEngine().playEffect(app, raw.fly);
			flyUp();
			if (!is_started) {
				this.schedule("nextPosition", interval_time);
				this.schedule("updateFlower");
				this.schedule("startFlower", flower_interval);
				is_started = true;
			}
			return super.ccTouchesBegan(event);
		}

		public void clean() {
			// stop schedule task
			this.unschedule("nextPosition");
			this.unschedule("updateFlower");
			this.unschedule("startFlower");

			// reset start flag
			is_started = false;
			// reset the miss number
			miss = 0;
			// reset speed
			speed = 0;
			// reset the bird state
			CGPoint pnt = CGPoint.ccp(winSize.width / 4, winSize.height / 2);
			curPos = pnt;
			bird_wave[0].setPosition(curPos);
			bird_wave[1].setPosition(curPos);
			// bird_wave[2].setPosition(curPos);
			bird_wave[0].runAction(CCShow.action());
			bird_wave[1].runAction(CCHide.action());
			// bird_wave[2].runAction(CCHide.action());
			// reset the flowers
			Iterator<CCSprite> spriteIter = flowerBuf.iterator();
			Iterator<FlowerState> stateIter = flowerState.iterator();
			Iterator<CCSprite> bigSpriteIter = bigFlowerBuf.iterator();
			while (spriteIter.hasNext() && stateIter.hasNext()
					&& bigSpriteIter.hasNext()) {
				FlowerState state = stateIter.next();
				CCSprite sprite = spriteIter.next();
				CCSprite bigSprite = bigSpriteIter.next();
				state.state = 0;
				sprite.runAction(CCHide.action());
				bigSprite.runAction(CCHide.action());
			}
			// reset power and spirit
			power = 100;
			spirit = Constants.levelSpirit[2];
			labelPower.setString(powerStr + ":" + power);
			labelSpirit.setString(spiritStr + ":" + spirit);
		}

		@Override
		public boolean ccTouchesEnded(MotionEvent event) {
			// TODO Auto-generated method stub
			flyUp();
			return super.ccTouchesEnded(event);
		}

		@Override
		public boolean ccTouchesMoved(MotionEvent event) {
			// TODO Auto-generated method stub
			return super.ccTouchesMoved(event);
		}

		@Override
		public void onEnter() {
			super.onEnter();

			SoundEngine.sharedEngine().playSound(app, raw.ground, true);
		}

		@Override
		public void onExit() {
			super.onExit();
			SoundEngine.sharedEngine().pauseSound();
		}

		public void nextPosition(float delta) {
			CGPoint flyDeltaVec = CGPoint.ccp(0, speed * interval_time
					* pixels_per_meter);
			CGPoint dstPnt = CGPoint.ccpAdd(curPos, flyDeltaVec);
			curPos = dstPnt;
			bird_wave[0].setPosition(curPos);
			bird_wave[1].setPosition(curPos);
			// bird_wave[2].setPosition(curPos);
			CCShow show = CCShow.action();
			bird_wave[ids[cur]].runAction(show);
			speed += accel_speed;
			if (curPos.y <= 0 || curPos.y >= winSize.height) {
				clean();
				if (curPos.y <= 0) {
					app.gameOver("You fell on the ground and died. ");
				} else {
					app.gameOver("You are not F22 or J20. ");
				}
			}
		}

		public void updateFlower(float delta) {
			Iterator<CCSprite> spriteIter = flowerBuf.iterator();
			Iterator<CCSprite> bigSpriteIter = bigFlowerBuf.iterator();
			Iterator<FlowerState> stateIter = flowerState.iterator();
			int id = 0;
			while (spriteIter.hasNext() && stateIter.hasNext()
					&& bigSpriteIter.hasNext()) {
				FlowerState state = stateIter.next();
				CCSprite sprite = spriteIter.next();
				CCSprite bigSprite = bigSpriteIter.next();
				if (state.equals(1)) {
					CGPoint pos = sprite.getPosition();
					pos = CGPoint.ccpAdd(pos,
							CGPoint.ccpMult(flowerSpeed, delta));
					if (pos.x <= 0) {
						state.state = 0;
						sprite.setPosition(CGPoint.ccp(winSize.width,
								winSize.height / 2));
						sprite.runAction(CCHide.action());
						miss++;
						if (miss >= missThreshold) {
							clean();
							app.gameOver("You have wasted too much opportunities.");
						}
					} else if (birdGetFlower(pos, id)) {
						state.state = 2;
						// sprite.runAction(CCHide.action());
						birdBloomFlower(sprite, bigSprite, id);
					} else {
						sprite.setPosition(pos);
						bigSprite.setPosition(pos);
						sprite.runAction(CCShow.action());
					}
				} else if (state.equals(2)) {
					CGPoint pos = bigSprite.getPosition();
					pos = CGPoint.ccpAdd(pos,
							CGPoint.ccpMult(flowerSpeed, delta));
					if (pos.x <= 0) {
						state.state = 0;
						bigSprite.setPosition(CGPoint.ccp(winSize.width,
								winSize.height / 2));
						bigSprite.runAction(CCHide.action());
					} else {
						sprite.setPosition(pos);
						bigSprite.setPosition(pos);
						bigSprite.runAction(CCShow.action());
					}
				}
				id++;
			}
		}

		private void birdBloomFlower(CCSprite sprite, CCSprite bigSprite, int id) {
			// TODO Auto-generated method stub
			SoundEngine.sharedEngine().playEffect(app, raw.eat);
			sprite.runAction(CCHide.action());
			bigSprite.runAction(CCShow.action());
			spirit += flowerSpirit[0];
			updateSpeed(spirit);
			if (spirit >= spiritThreshold) {
				FinalScene();
			}
			labelSpirit.setString(spiritStr + ":" + spirit);
		}

		private void updateSpeed(int sp) {
			// TODO Auto-generated method stub
			flowerSpeed.x = -(winSize.width / 2 + winSize.width
					* (sp - Constants.levelSpirit[2])
					/ (2 * Constants.levelSpirit[3] - Constants.levelSpirit[2]));
		}

		private void FinalScene() {
			SoundEngine.sharedEngine().playEffect(app, raw.upgrade);
			clean();
			app.switchScene(5);
		}

		private boolean birdGetFlower(CGPoint pos, int id) {
			// TODO Auto-generated method stub

			if (CGPoint.ccpDistance(pos, curPos) < radiux) {
				return true;
			}
			for (int i = 0; i < numCtrlPoints; i++) {
				if (CGPoint.ccpDistance(pos,
						CGPoint.ccpAdd(curPos, ctrlPoints[i])) < radiux) {
					return true;
				}
			}
			return false;
		}

		public void startFlower(float delta) {
			int id = Math.abs(rand.nextInt()) % (totalFlower);
			int n = 0;
			while (!flowerState.get(id).equals(0) && n++ < (totalFlower)) {
				id = (id + 1) % (totalFlower);
			}
			if (n < (totalFlower)) {
				CCSprite sprite = flowerBuf.get(id);
				CCSprite bigSprite = bigFlowerBuf.get(id);
				CGPoint pos = CGPoint.ccp(winSize.width, winSize.height / 4
						+ Math.abs(rand.nextInt()) % (winSize.height / 2));
				sprite.setPosition(pos);
				bigSprite.setPosition(pos);
				sprite.runAction(CCShow.action());
				bigSprite.runAction(CCHide.action());
				flowerState.set(id, new FlowerState(1));
			}
		}

		public void flyUp() {
			CCHide hide = CCHide.action();
			CCShow show = CCShow.action();

			bird_wave[ids[cur]].runAction(hide);
			cur = (++cur) % total;
			bird_wave[ids[cur]].runAction(show);
			speed += fly_speed_delta;
			if (speed < 0) {
				speed = 0;
			}

		}

	}

	class FinalLayer extends CCLayer {
		private CCSprite bg = null;
		CGSize winSize = null;

		FinalLayer() {
			winSize = CCDirector.sharedDirector().winSize();
			CGPoint pnt = CGPoint.ccp(winSize.width / 2, winSize.height / 2);
			bg = CCSprite.sprite("final.jpg");
			bg.setPosition(pnt);
			this.addChild(bg);

			CCMenuItem itemEnd = CCMenuItemImage.item("end.png", "end.png",
					this, "callBackDoNothing");
			CCMenuItem itemBack = CCMenuItemImage.item("back.png",
					"back_sel.png", this, "callBackGameOver");
			CCMenu menu = CCMenu.menu(itemEnd, itemBack);
			menu.alignItemsVertically();
			this.addChild(menu);
		}

		public void callBackDoNothing(Object sender) {

		}

		public void callBackGameOver(Object sender) {
			app.switchScene(0);
		}
	}

	public class LauncherMenuLayer extends CCLayer {
		private CCSprite bg = null;
		private CGSize winSize = null;
		private int grade = app.gameState.getGrade();
		CCMenu selMenu = null;

		public LauncherMenuLayer() {
			winSize = CCDirector.sharedDirector().winSize();
			CGPoint pnt = CGPoint.ccp(winSize.width / 2, winSize.height / 2);
			bg = CCSprite.sprite("menubg.jpg");
			bg.setPosition(pnt);
			this.addChild(bg);

			CCMenuItem itemBird = CCMenuItemImage.item("menu_bird.png",
					"menu_bird_sel.png", this, "callBackBird");
			CCMenuItem itemFairy = null;
			CCMenuItem itemGirl = null;
			if (grade >= 1) {
				itemFairy = CCMenuItemImage.item("menu_fairy.png",
						"menu_fairy_sel.png", this, "callBackFairy");
			} else {
				itemFairy = CCMenuItemImage.item("menu_fairy_gray.png",
						"menu_fairy_gray.png", this, "doNothing()");
			}
			if (grade >= 2) {
				itemGirl = CCMenuItemImage.item("menu_girl.png",
						"menu_girl_sel.png", this, "callBackGirl");
			} else {
				itemGirl = CCMenuItemImage.item("menu_girl_gray.png",
						"menu_girl_gray.png", this, "doNothing");
			}
			selMenu = CCMenu.menu(itemBird, itemFairy, itemGirl);
			selMenu.alignItemsHorizontally(20f);
			this.addChild(selMenu);

			CCMenuItem itemQuit = CCMenuItemImage.item("quit_mini.png",
					"quit_mini_sel.png", this, "callBackQuit");
			CCMenu menu = CCMenu.menu(itemQuit);
			menu.setPosition(CGPoint.ccp(
					winSize.width - itemQuit.getBoundingBox().size.width,
					itemQuit.getBoundingBox().size.height));
			menu.alignItemsVertically();
			this.addChild(menu);
		}

		public void callBackBird(Object sender) {
			SoundEngine.sharedEngine().playEffect(app, raw.upgrade);
			app.switchScene(1);
		}

		public void callBackFairy(Object sender) {
			SoundEngine.sharedEngine().playEffect(app, raw.upgrade);
			app.switchScene(2);
		}

		public void callBackGirl(Object sender) {
			SoundEngine.sharedEngine().playEffect(app, raw.upgrade);
			app.switchScene(3);
		}

		public void doNothing(Object sender) {

		}

		public void callBackQuit(Object sender) {
			SoundEngine.sharedEngine().playEffect(app, raw.die);
			super.onExit();
			CCDirector.sharedDirector().end();
			app.onDestroy();
			System.exit(0);
		}

		public void setGrade(int grade) {
			this.grade = grade;
		}

		public int getGrade() {
			return this.grade;
		}

		public void refreshMenu() {
			this.removeChild(selMenu, true);
			CCMenuItem itemBird = CCMenuItemImage.item("menu_bird.png",
					"menu_bird_sel.png", this, "callBackBird");
			CCMenuItem itemFairy = null;
			CCMenuItem itemGirl = null;
			if (grade >= 1) {
				itemFairy = CCMenuItemImage.item("menu_fairy.png",
						"menu_fairy_sel.png", this, "callBackFairy");
			} else {
				itemFairy = CCMenuItemImage.item("menu_fairy_gray.png",
						"menu_fairy_gray.png", this, "doNothing()");
			}
			if (grade >= 2) {
				itemGirl = CCMenuItemImage.item("menu_girl.png",
						"menu_girl_sel.png", this, "callBackGirl");
			} else {
				itemGirl = CCMenuItemImage.item("menu_girl_gray.png",
						"menu_girl_gray.png", this, "doNothing");
			}
			selMenu = CCMenu.menu(itemBird, itemFairy, itemGirl);
			selMenu.alignItemsHorizontally(20f);
			this.addChild(selMenu);
		}
	}

}