利用Jbox2D物理引擎实现愤怒的小鸟

来源:互联网 发布:捕鱼游戏网页版源码 编辑:程序博客网 时间:2024/05/21 22:55

    要导入jar包:jbox2d-library-2.2.1.1.jar

1、先创建util工具类

(1)

public class Globals {public static int SCREEN_WIDTH;public static int SCREEN_HEIGHT;public static int RATE;public static float PIECE_WIDTH;public static float PIECE_HEIGHT;public static boolean birdCenterFlag = false;public static void init(Activity a) {SCREEN_WIDTH = a.getWindowManager().getDefaultDisplay().getWidth();SCREEN_HEIGHT = a.getWindowManager().getDefaultDisplay().getHeight();RATE = 10;PIECE_WIDTH = SCREEN_WIDTH / 10f;PIECE_HEIGHT = SCREEN_HEIGHT / 6f;}}
(2)

public class ImageUtils {private static Bitmap background;private static Bitmap landImg;private static Bitmap[] wood = new Bitmap[3];private static Bitmap[] glass = new Bitmap[4];private static Bitmap[] birdImgs = new Bitmap[4];private static Bitmap dangongImg;private static Bitmap[] woodDestory = new Bitmap[15];public static void init(Activity a) {background = changeSize(BitmapFactory.decodeResource(a.getResources(),R.drawable.main_bg), Globals.SCREEN_WIDTH * 2,Globals.SCREEN_HEIGHT * 2);landImg = changeSize(BitmapFactory.decodeResource(a.getResources(),R.drawable.ground), Globals.SCREEN_WIDTH, Globals.PIECE_HEIGHT);wood[0] = changeSize(BitmapFactory.decodeResource(a.getResources(),R.drawable.wood_hen), Globals.PIECE_WIDTH * 3,Globals.PIECE_HEIGHT / 2);wood[1] = changeSize(BitmapFactory.decodeResource(a.getResources(),R.drawable.wood_hen_1), Globals.PIECE_WIDTH * 3,Globals.PIECE_HEIGHT / 2);wood[2] = changeSize(BitmapFactory.decodeResource(a.getResources(),R.drawable.wood_hen_2), Globals.PIECE_WIDTH * 3,Globals.PIECE_HEIGHT / 2);glass[0] = changeSize(BitmapFactory.decodeResource(a.getResources(),R.drawable.glass_0), Globals.PIECE_WIDTH * 2,Globals.PIECE_HEIGHT * 1.5f);glass[1] = changeSize(BitmapFactory.decodeResource(a.getResources(),R.drawable.glass_1), Globals.PIECE_WIDTH * 2,Globals.PIECE_HEIGHT * 1.5f);glass[2] = changeSize(BitmapFactory.decodeResource(a.getResources(),R.drawable.glass_2), Globals.PIECE_WIDTH * 2,Globals.PIECE_HEIGHT * 1.5f);glass[3] = changeSize(BitmapFactory.decodeResource(a.getResources(),R.drawable.glass_3), Globals.PIECE_WIDTH * 2,Globals.PIECE_HEIGHT * 1.5f);birdImgs[0] = changeSize(BitmapFactory.decodeResource(a.getResources(),R.drawable.bird_0), Globals.PIECE_WIDTH, Globals.PIECE_HEIGHT);dangongImg = changeSize(BitmapFactory.decodeResource(a.getResources(),R.drawable.dangong), Globals.PIECE_WIDTH / 2,Globals.PIECE_HEIGHT * 3);for (int i = 0; i < 15; i++) {try {woodDestory[i] = changeSize(BitmapFactory.decodeStream(a.getAssets().open("image" + (20 + i * 2) + ".png")),Globals.PIECE_WIDTH * 1.5f, Globals.PIECE_HEIGHT * 3);} catch (Exception e) {e.printStackTrace();}}}public static Bitmap getWoodDestory(int index) {return woodDestory[index];}public static Bitmap getBirdImg(int type) {return birdImgs[type - 1];}private static Bitmap changeSize(Bitmap source, float overWidth,float overHeight) {Matrix m = new Matrix();m.postScale(overWidth / source.getWidth(),overHeight / source.getHeight());return Bitmap.createBitmap(source, 0, 0, source.getWidth(),source.getHeight(), m, false);}public static Bitmap getBackground() {return background;}public static Bitmap getLandImg() {return landImg;}public static Bitmap getWood(int index) {return wood[index];}public static Bitmap getGlass(int index) {return glass[index];}public static Bitmap getDangongImg() {return dangongImg;}}
(3)

public class JBoxUtils {public static World world;public static int STONE_TYPE = 1;public static int WOOD_TYPE = 2;public static int LAND_TYPE = 3;public static int GLASS_TYPE = 4;public static int BIRD_TYPE = 5;public static int PIG_TYPE = 6;public static void init() {world = new World(new Vec2(0, 10f));// 设置世界不会自动休眠world.setAllowSleep(true);world.setContactListener(new ContactListener() {@Overridepublic void preSolve(Contact arg0, Manifold arg1) {}@Overridepublic void postSolve(Contact arg0, ContactImpulse arg1) {// 在这里进行自己的处理,通过参数接收到哪两个对象进行的碰撞,并取得碰撞时产生的冲力Object objA = arg0.m_fixtureA.getBody().m_userData;Object objB = arg0.m_fixtureB.getBody().m_userData;float li = arg1.normalImpulses[0];if (li > 500) {if (objA instanceof Item) {// 就是物体// 打印哪些物体碰撞,冲力是多少System.out.println(objB.getClass().getName() + " 与  "+ objA.getClass().getName() + " 发生碰撞 , 受力为 : "+ arg1.normalImpulses[0]);// 减血Item i = (Item) objA;i.setLife(i.getLife() - li / 50);}if (objB instanceof Item) {System.out.println(objA.getClass().getName() + " 与  "+ objB.getClass().getName() + " 发生碰撞 , 受力为 : "+ arg1.normalImpulses[0]);Item i = (Item) objB;i.setLife(i.getLife() - li / 50);}}}@Overridepublic void endContact(Contact arg0) {}@Overridepublic void beginContact(Contact arg0) {}});}public static Body createCircle(float r, float x, float y, int type,float angle, boolean isStatic) {CircleShape shape = new CircleShape();shape.m_radius = r / Globals.RATE;return createBody(shape, type, x, y, angle, isStatic);}public static Body createBox(float width, float height, float x, float y,float angle, int type, boolean isStatic) {PolygonShape shape = new PolygonShape();shape.setAsBox(width / 2 / Globals.RATE, height / 2 / Globals.RATE);return createBody(shape, type, x, y, angle, isStatic);}private static Body createBody(Shape shape, int type, float x, float y,float angle, boolean isStatic) {FixtureDef def = new FixtureDef();def.shape = shape;switch (type) {case 1:def.density = 7.9f;def.restitution = 0.2f;def.friction = 0.1f;break;case 2:def.density = 0.8f;def.restitution = 0.4f;def.friction = 0.2f;break;case 3:def.density = 0f;def.restitution = 0.5f;def.friction = 0.5f;break;case 4:def.density = 1.5f;def.restitution = 0.2f;def.friction = 0.1f;break;case 5:case 6:def.density = 0.95f;def.restitution = 0.2f;def.friction = 0.5f;break;}BodyDef bd = new BodyDef();// 旋转的弧度bd.angle = angle;bd.position = new Vec2(x / Globals.RATE, y / Globals.RATE);Body b = world.createBody(bd);b.createFixture(def);if (isStatic) {b.setType(BodyType.STATIC);} else {b.setType(BodyType.DYNAMIC);}return b;}}

(4)

public class MusicUtils {private static MediaPlayer back;private static SoundPool pool;private static Map<String, Integer> allSound = new HashMap<String, Integer>();public static void init(Activity a) {}public static void playBackMusic() {back.start();}public static void pauseBackMusic() {back.pause();}public static void playSound(String key) {pool.play(allSound.get(key), 1, 1, 1, 0, 1);}public static void recycle() {try {back.release();pool.release();} catch (Exception e) {e.printStackTrace();}}}
2、创建vo类

(1)

public class Bird {private Body body;private float r;private int type;public Bird(int type) {switch (type) {case 1:r = Globals.PIECE_WIDTH / 2;break;}this.type = type;}public void draw(Canvas canvas, Paint paint, Point nowPosition) {canvas.save();canvas.rotate((float) (body.getAngle() * 180 / Math.PI),body.getPosition().x * Globals.RATE + nowPosition.x,body.getPosition().y * Globals.RATE + nowPosition.y);canvas.drawBitmap(ImageUtils.getBirdImg(type), body.getPosition().x* Globals.RATE - r + nowPosition.x, body.getPosition().y* Globals.RATE - r + nowPosition.y, paint);if (Globals.birdCenterFlag) {// 保证正在飞行的鸟的坐标在屏幕正中nowPosition.x = (int) -(body.getPosition().x * Globals.RATE - Globals.SCREEN_WIDTH / 2);nowPosition.y = (int) -(body.getPosition().y * Globals.RATE - Globals.SCREEN_HEIGHT / 2);if (nowPosition.x > 0) {nowPosition.x = 0;}if (nowPosition.y > 0) {nowPosition.y = 0;}if (nowPosition.x < -Globals.SCREEN_WIDTH) {nowPosition.x = -Globals.SCREEN_WIDTH;}if (nowPosition.y < -Globals.SCREEN_HEIGHT) {nowPosition.y = -Globals.SCREEN_HEIGHT;}}canvas.restore();}public Body getBody() {return body;}public void setBody(Body body) {this.body = body;this.body.m_userData = this;}public int getType() {return type;}public void setType(int type) {this.type = type;}public float getR() {return r;}public void setR(float r) {this.r = r;}}
(2)

public abstract class Item {private Body body;private float width;private float height;private float life = 500;private int animIndex = 0;private int countDown = 2;// 记录销毁时的坐标,以及弧度private float[] destoryPoint;private float destoryAngle;public void draw(Canvas canvas, Paint paint, Point nowPosition) {// 前后的画布操作,在这里实现// 旋转画布canvas.save();if (life > 0) {canvas.rotate((float) (body.getAngle() * 180 / Math.PI),body.getPosition().x * Globals.RATE + nowPosition.x,body.getPosition().y * Globals.RATE + nowPosition.y);} else {// canvas.rotate((float) (destoryAngle * 180 / Math.PI),// body.getPosition().x * Globals.RATE + nowPosition.x,// body.getPosition().y * Globals.RATE + nowPosition.y);}drawItem(canvas, paint, nowPosition);canvas.restore();}public abstract void drawItem(Canvas canvas, Paint paint, Point nowPosition);public Body getBody() {return body;}public void setBody(Body body) {this.body = body;this.body.m_userData = this;}public float getWidth() {return width;}public void setWidth(float width) {this.width = width;}public float getHeight() {return height;}public void setHeight(float height) {this.height = height;}public float getLife() {return life;}public void setLife(float life) {this.life = life;if (life <= 0) {if (destoryPoint == null) {destoryPoint = new float[2];destoryPoint[0] = body.getPosition().x * Globals.RATE;destoryPoint[1] = body.getPosition().y * Globals.RATE;destoryAngle = body.getAngle();}// 当生命小于0时,需要将body销毁JBoxUtils.world.destroyBody(body);}}public int getAnimIndex() {return animIndex;}public void setAnimIndex(int animIndex) {this.animIndex = animIndex;}public int getCountDown() {return countDown;}public void setCountDown(int countDown) {this.countDown = countDown;}public float[] getDestoryPoint() {return destoryPoint;}public void setDestoryPoint(float[] destoryPoint) {this.destoryPoint = destoryPoint;}public float getDestoryAngle() {return destoryAngle;}public void setDestoryAngle(float destoryAngle) {this.destoryAngle = destoryAngle;}}

(3)

public class Glass extends Item {public Glass(Body body) {setBody(body);setWidth(Globals.PIECE_WIDTH * 2);setHeight(Globals.PIECE_HEIGHT * 1.5f);setLife(300);}@Overridepublic void drawItem(Canvas canvas, Paint paint, Point nowPosition) {if (getLife() > 200) {canvas.drawBitmap(ImageUtils.getGlass(0), getBody().getPosition().x* Globals.RATE - getWidth() / 2 + nowPosition.x, getBody().getPosition().y* Globals.RATE- getHeight()/ 2+ nowPosition.y, paint);} else if (getLife() > 100) {canvas.drawBitmap(ImageUtils.getGlass(1), getBody().getPosition().x* Globals.RATE - getWidth() / 2 + nowPosition.x, getBody().getPosition().y* Globals.RATE- getHeight()/ 2+ nowPosition.y, paint);} else if (getLife() > 50) {canvas.drawBitmap(ImageUtils.getGlass(2), getBody().getPosition().x* Globals.RATE - getWidth() / 2 + nowPosition.x, getBody().getPosition().y* Globals.RATE- getHeight()/ 2+ nowPosition.y, paint);} else if (getLife() > 0) {canvas.drawBitmap(ImageUtils.getGlass(3), getBody().getPosition().x* Globals.RATE - getWidth() / 2 + nowPosition.x, getBody().getPosition().y* Globals.RATE- getHeight()/ 2+ nowPosition.y, paint);} else {}}}

(4)

public class Wood extends Item {public Wood(Body body) {setBody(body);setWidth(Globals.PIECE_WIDTH * 3);setHeight(Globals.PIECE_HEIGHT / 2);setLife(100);}public void drawItem(Canvas canvas, Paint paint, Point nowPosition) {if (getLife() > 300) {canvas.drawBitmap(ImageUtils.getWood(0), getBody().getPosition().x* Globals.RATE - getWidth() / 2 + nowPosition.x, getBody().getPosition().y* Globals.RATE- getHeight()/ 2+ nowPosition.y, paint);} else if (getLife() > 100) {canvas.drawBitmap(ImageUtils.getWood(1), getBody().getPosition().x* Globals.RATE - getWidth() / 2 + nowPosition.x, getBody().getPosition().y* Globals.RATE- getHeight()/ 2+ nowPosition.y, paint);} else if (getLife() > 0) {canvas.drawBitmap(ImageUtils.getWood(2), getBody().getPosition().x* Globals.RATE - getWidth() / 2 + nowPosition.x, getBody().getPosition().y* Globals.RATE- getHeight()/ 2+ nowPosition.y, paint);} else {setCountDown(getCountDown() - 1);if (getCountDown() == 0) {setCountDown(2);setAnimIndex(getAnimIndex() + 1);if (getAnimIndex() == 15) {setAnimIndex(14);}}canvas.drawBitmap(ImageUtils.getWoodDestory(getAnimIndex()),getDestoryPoint()[0] - Globals.PIECE_WIDTH / 2+ nowPosition.x, getDestoryPoint()[1]- Globals.PIECE_HEIGHT + nowPosition.y, paint);}}}
3、创建view类

public class MainView extends View {private Point nowPosition;private Point startNowPosition;private Point startPoint;private List<Body> landBody = new ArrayList<Body>();private List<Item> allItem = new ArrayList<Item>();private Bird bird;// 记录手指的坐标private float[] fingerPoint = new float[2];// 保存弹弓的相关坐标private float[] dangongCenterPoint = new float[2];private float[] dangongLeftPoint = new float[2];private float[] dangongRightPoint = new float[2];// 声明一个标志位, 用来保存当前弹弓的状态private boolean isBird = false;public MainView(Context context, AttributeSet attrs) {super(context, attrs);nowPosition = new Point(0, -Globals.SCREEN_HEIGHT);this.setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View v) {}});this.setOnTouchListener(new OnTouchListener() {@Overridepublic boolean onTouch(View v, MotionEvent event) {float x = event.getX();float y = event.getY();if (event.getAction() == MotionEvent.ACTION_DOWN) {// 判断按下的位置是否在弹弓的附近if (Math.abs(x - nowPosition.x - dangongCenterPoint[0]) <= Globals.PIECE_WIDTH&& Math.abs(y - nowPosition.y- dangongCenterPoint[1]) <= Globals.PIECE_HEIGHT) {isBird = true;} else {startPoint = new Point((int) x, (int) y);startNowPosition = new Point(nowPosition.x,nowPosition.y);// 当前要移动屏幕位置Globals.birdCenterFlag = false;}} else if (event.getAction() == MotionEvent.ACTION_MOVE) {if (isBird) {fingerPoint[0] = x - nowPosition.x;fingerPoint[1] = y - nowPosition.y;} else {nowPosition.x = startNowPosition.x+ (int) (startPoint.x - x);nowPosition.y = startNowPosition.y+ (int) (startPoint.y - y);}} else if (event.getAction() == MotionEvent.ACTION_UP) {if (isBird) {// 建立一个新的Birdbird = new Bird(1);// 设置刚体对象bird.setBody(JBoxUtils.createCircle(bird.getR(), x- nowPosition.x, y - nowPosition.y,JBoxUtils.BIRD_TYPE, 0, false));// 提供一个冲力bird.getBody().applyLinearImpulse(new Vec2(-(x - nowPosition.x - dangongCenterPoint[0]) * 25,-(y - nowPosition.y - dangongCenterPoint[1]) * 25),bird.getBody().getWorldCenter());isBird = false;// 当创建一个新的飞行的鸟时,需要以其为中心Globals.birdCenterFlag = true;} else {nowPosition.x = startNowPosition.x+ (int) (startPoint.x - x);nowPosition.y = startNowPosition.y+ (int) (startPoint.y - y);}}if (nowPosition.x > 0) {nowPosition.x = 0;}if (nowPosition.y > 0) {nowPosition.y = 0;}if (nowPosition.x < -Globals.SCREEN_WIDTH) {nowPosition.x = -Globals.SCREEN_WIDTH;}if (nowPosition.y < -Globals.SCREEN_HEIGHT) {nowPosition.y = -Globals.SCREEN_HEIGHT;}postInvalidate();return false;}});init();// 初始化弹弓的坐标dangongCenterPoint[0] = Globals.PIECE_WIDTH * 4.25f;dangongLeftPoint[0] = Globals.PIECE_WIDTH * 4.125f;dangongRightPoint[0] = Globals.PIECE_WIDTH * 4.375f;dangongCenterPoint[1] = Globals.PIECE_HEIGHT * 8.75f;dangongLeftPoint[1] = Globals.PIECE_HEIGHT * 8.75f;dangongRightPoint[1] = Globals.PIECE_HEIGHT * 8.75f;}private void init() {// 初始化关卡JBoxUtils.init();landBody.clear();// 这里写死两个固定地面物体landBody.add(JBoxUtils.createBox(Globals.SCREEN_WIDTH,Globals.PIECE_HEIGHT, Globals.SCREEN_WIDTH / 2,Globals.PIECE_HEIGHT * 11.5f, 0, JBoxUtils.LAND_TYPE, true));landBody.add(JBoxUtils.createBox(Globals.SCREEN_WIDTH,Globals.PIECE_HEIGHT, Globals.SCREEN_WIDTH * 1.5f,Globals.PIECE_HEIGHT * 11.5f, 0, JBoxUtils.LAND_TYPE, true));// 为地面也加入一些数据landBody.get(0).m_userData = "地面";landBody.get(1).m_userData = "地面";// 建立木头,旋转90度Wood w = new Wood(JBoxUtils.createBox(Globals.PIECE_WIDTH * 3,Globals.PIECE_HEIGHT / 2, Globals.PIECE_WIDTH * 9.25f,Globals.PIECE_HEIGHT * 9.5f, (float) (Math.PI / 2),JBoxUtils.WOOD_TYPE, false));allItem.add(w);// w = new Wood(JBoxUtils.createBox(Globals.PIECE_WIDTH * 3,// Globals.PIECE_HEIGHT / 2, Globals.PIECE_WIDTH * 10.25f,// Globals.PIECE_HEIGHT * 9.5f, (float) (Math.PI / 2),// JBoxUtils.WOOD_TYPE, false));//// allItem.add(w);//// Glass g = new Glass(JBoxUtils.createBox(Globals.PIECE_WIDTH * 2,// Globals.PIECE_HEIGHT * 1.5f, Globals.PIECE_WIDTH * 10f,// Globals.PIECE_HEIGHT * 7.25f, 0, JBoxUtils.GLASS_TYPE, false));// allItem.add(g);// bird = new Bird(1);// bird.setBody(JBoxUtils.createCircle(bird.getR(),// Globals.PIECE_WIDTH * 1f, Globals.PIECE_HEIGHT * 9.5f,// JBoxUtils.BIRD_TYPE, 0, false));//// // 为鸟施加一个冲力// bird.getBody().applyLinearImpulse(new Vec2(5000, -1000),// bird.getBody().getWorldCenter());}@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);Paint paint = new Paint();// 绘制背景if (nowPosition != null) {canvas.drawBitmap(ImageUtils.getBackground(), nowPosition.x,nowPosition.y, paint);// 循环绘制地面Iterator<Body> iterLand = landBody.iterator();while (iterLand.hasNext()) {Body b = iterLand.next();canvas.drawBitmap(ImageUtils.getLandImg(), b.getPosition().x* Globals.RATE - Globals.SCREEN_WIDTH / 2+ nowPosition.x, b.getPosition().y * Globals.RATE- Globals.PIECE_HEIGHT / 2 + nowPosition.y, paint);}Iterator<Item> iterItem = allItem.iterator();while (iterItem.hasNext()) {Item i = iterItem.next();i.draw(canvas, paint, nowPosition);if (i.getLife() <= 0 && i.getAnimIndex() == 14) {iterItem.remove();}}if (bird != null) {bird.draw(canvas, paint, nowPosition);}// 绘制弹弓的线if (isBird) {paint.setColor(Color.RED);canvas.drawLine(fingerPoint[0] + nowPosition.x, fingerPoint[1]+ nowPosition.y, dangongRightPoint[0] + nowPosition.x,dangongRightPoint[1] + nowPosition.y, paint);canvas.drawBitmap(ImageUtils.getBirdImg(1), fingerPoint[0]+ nowPosition.x - Globals.PIECE_WIDTH / 2,fingerPoint[1] + nowPosition.y - Globals.PIECE_HEIGHT/ 2, paint);canvas.drawLine(fingerPoint[0] + nowPosition.x, fingerPoint[1]+ nowPosition.y, dangongLeftPoint[0] + nowPosition.x,dangongLeftPoint[1] + nowPosition.y, paint);}// 绘制弹弓图片canvas.drawBitmap(ImageUtils.getDangongImg(), Globals.PIECE_WIDTH* 4 + nowPosition.x, Globals.PIECE_HEIGHT * 8+ nowPosition.y, paint);}}}

4、Activity类

public class MainActivity extends Activity {private MainView mainView;private boolean flag = true;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);Globals.init(this);ImageUtils.init(this);MusicUtils.init(this);setContentView(R.layout.activity_main);mainView = (MainView) findViewById(R.id.main_view);Thread t = new Thread() {@Overridepublic void run() {while (flag) {try {JBoxUtils.world.step(1.0f / 30, 3, 8);mainView.postInvalidate();Thread.sleep(33);} catch (Exception e) {e.printStackTrace();}}}};t.start();}}

5、布局

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:tools="http://schemas.android.com/tools"    android:layout_width="match_parent"    android:layout_height="match_parent" >    <org.lsp.angrybird.view.MainView        android:id="@+id/main_view"        android:layout_width="match_parent"        android:layout_height="match_parent" /></RelativeLayout>




0 0