android 2d物理发动机-APEngine
android 2d物理引擎-APEngine? package Test.APEngineTestimport android.graphics.Canvasimport androi
android 2d物理引擎-APEngine
?
package Test.APEngineTest;import android.graphics.Canvas;import android.graphics.Paint;import android.util.Log;import android.view.KeyEvent;import android.view.SurfaceView;import android.view.SurfaceHolder;import android.content.Context;import android.graphics.Color;import android.graphics.Paint.Style;import java.lang.Runnable;import java.util.ArrayList;import ape.*;public class ApeTest extends SurfaceView implements Runnable, SurfaceHolder.Callback{// APEngine 世界private APEngine APEngine = new APEngine();// 两个轮子private SpringConstraint wheelConnector;private WheelParticle wheelParticleA;private WheelParticle wheelParticleB;// 车身private RectangleParticle rotatingRect;// 世界中需要刷新的所有物理列表private ArrayList paintQueue;private Canvas mCanvas = null;private Paint mPaint = null;SurfaceHolder mSurfaceHolder = null; public static final int SCREEN_WIDTH = 320;public static final int SCREEN_HEIGHT= 480;public static final int PLAY_HEIGHT = 400; public static final int SPEED = 15;public static final double keySpeed = 0.2;//计算帧率//private long mFPSLockTime = 0;private long mFPSShowTime = 0;//private long mNowTime = 0;//现在的时间private int mLoopCount = 0;//循环次数private float mFPS = 0.0f;//帧速//private float mFPSTime = (1000.0f/30);//每帧最大执行时间(默认30帧)private Paint mFPSPaint = new Paint();public ApeTest(Context context){super(context);setFocusable(true);setFocusableInTouchMode(true);mSurfaceHolder = this.getHolder();mSurfaceHolder.addCallback(this); mPaint = new Paint(); mPaint.setAntiAlias(true);mPaint.setColor(Color.BLACK);mPaint.setStyle(Style.STROKE);APEngine.setDefaultPaint(mPaint); InitWorld(); }//end of func public void InitWorld() { // set up the events, main loop handler, and the engine. you don't have to use// enterframe. you just need to call the ApeEngine.step() method wherever// and however your handling your program cycle.// the argument here is the deltaTime value. Higher values result in faster simulations.APEngine.init((double)1/4);// SELECTIVE is better for dealing with lots of little particles colliding, // as in the little rects and circles in this exampleAPEngine.setCollisionResponseMode(APEngine.SELECTIVE);// gravity -- particles of varying masses are affected the sameAPEngine.addMasslessForce(new Vector(0,3));// surfacesRectangleParticle floor = new RectangleParticle(325,324,649,50,0,true,1,0.3,0);APEngine.addParticle(floor);RectangleParticle floorBumpA = new RectangleParticle(400,295,90,30, 0.4,true,1,0.3,0);APEngine.addParticle(floorBumpA);RectangleParticle floorBumpB = new RectangleParticle(330,295,90,30,-0.4,true,1,0.3,0);//APEngine.addParticle(floorBumpB);RectangleParticle floorLeftAngle = new RectangleParticle(80,290,120,20,0.5,true,1,0.3,0);APEngine.addParticle(floorLeftAngle);RectangleParticle leftWall = new RectangleParticle(15,99,30,500,0,true,1,0.3,0);APEngine.addParticle(leftWall);RectangleParticle rightWall = new RectangleParticle(634,99,30,500,0,true,1,0.3,0);APEngine.addParticle(rightWall);// 桥 开始点RectangleParticle bridgeStart = new RectangleParticle(80,70,150,25,0,true,1,0.3,0);APEngine.addParticle(bridgeStart);// 桥结束点RectangleParticle bridgeEnd = new RectangleParticle(380,70,100,25,0,true,1,0.3,0);APEngine.addParticle(bridgeEnd);RectangleParticle bridgeEndAngle = new RectangleParticle(455,102,100,25,0.8,true,1,0.3,0);APEngine.addParticle(bridgeEndAngle);RectangleParticle rightWallAngle = new RectangleParticle(595,102,100,25,-0.8,true,1,0.3,0);APEngine.addParticle(rightWallAngle);// 旋转矩形rotatorrotatingRect = new RectangleParticle(525,180,70,14,0,true,1,0.3,0);APEngine.addParticle(rotatingRect);// 小矩形RectangleParticle littleRect = new RectangleParticle(525,180,10,10,0,false,1,0.3,0);APEngine.addParticle(littleRect);// 把旋转矩形和小矩形用皮筋连接到一起SpringConstraint rotConnector = new SpringConstraint((AbstractParticle)rotatingRect.getCornerParticles().get(1), (AbstractParticle)littleRect, 0.2);APEngine.addConstraint(rotConnector);// bridgeCircleParticle bridgePA = new CircleParticle(200,70,4,false,1,0.3,0);APEngine.addParticle(bridgePA);CircleParticle bridgePB = new CircleParticle(240,70,4,false,1,0.3,0);APEngine.addParticle(bridgePB);CircleParticle bridgePC = new CircleParticle(280,70,4,false,1,0.3,0);APEngine.addParticle(bridgePC);SpringConstraint bridgeConnA = new SpringConstraint((AbstractParticle)bridgeStart.getCornerParticles().get(1), bridgePA, 0.9);bridgeConnA.setCollidable(true);bridgeConnA.setCollisionRectWidth(10);bridgeConnA.setCollisionRectScale(0.6);APEngine.addConstraint(bridgeConnA);SpringConstraint bridgeConnB = new SpringConstraint(bridgePA, bridgePB, 0.9);bridgeConnB.setCollidable(true);bridgeConnB.setCollisionRectWidth(10);bridgeConnB.setCollisionRectScale(0.6);APEngine.addConstraint(bridgeConnB);SpringConstraint bridgeConnC = new SpringConstraint(bridgePB, bridgePC, 0.9);bridgeConnC.setCollidable(true);bridgeConnC.setCollisionRectWidth(10);bridgeConnC.setCollisionRectScale(0.6);APEngine.addConstraint(bridgeConnC);SpringConstraint bridgeConnD = new SpringConstraint(bridgePC, (AbstractParticle)bridgeEnd.getCornerParticles().get(0), 0.9);bridgeConnD.setCollidable(true);bridgeConnD.setCollisionRectWidth(10);bridgeConnD.setCollisionRectScale(0.6);APEngine.addConstraint(bridgeConnD);// 汽车 wheelParticleA = new WheelParticle(60,10,20,false,1,0.3,0,1);wheelParticleA.setMass(2);APEngine.addParticle(wheelParticleA);wheelParticleB = new WheelParticle(140,10,20,false,1,0.3,0,1);wheelParticleB.setMass(2);APEngine.addParticle(wheelParticleB);wheelConnector = new SpringConstraint(wheelParticleA, wheelParticleB,0.5);wheelConnector.setCollidable(true);wheelConnector.setCollisionRectWidth((double)10);wheelConnector.setCollisionRectScale((double)0.9);APEngine.addConstraint(wheelConnector);// little boxesfor (int i = 0; i < 10; i++) {double px = (7 * i) + 120;APEngine.addParticle(new RectangleParticle(px,200,10,5,Math.random() * Math.PI,false,1.8,0.1,0.0));APEngine.addParticle(new CircleParticle(px+40,210,3.5,false,1.8,0.1,0.0));}/*After adding all the particles and constraints, you can retrieve them using the getXXX methods from the APEngine class. Then you can go through them and paint themwhen necessary. Alternatively you can keep track of them yourself by manually addingthem to your own lists.*/paintQueue = APEngine.getAll();}//end of funcpublic void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2, int arg3){}public void surfaceCreated(SurfaceHolder holder){Log.v("surfaceCreated()", "线程启动前");new Thread(this).start();}public void surfaceDestroyed(SurfaceHolder holder){//alive = false;}//触摸屏事件@Override public boolean onTouchEvent(android.view.MotionEvent event){ //XTouch.OnTouch(event.getAction(), event.getX(), event.getY());if (wheelParticleA==null || wheelParticleB==null) {return false;}if (event.getAction() == android.view.MotionEvent.ACTION_DOWN) {if (event.getX() < 240) {wheelParticleA.setAngularVelocity(-keySpeed);wheelParticleB.setAngularVelocity(-keySpeed);}else {wheelParticleA.setAngularVelocity(keySpeed);wheelParticleB.setAngularVelocity(keySpeed);}}else if (event.getAction() == android.view.MotionEvent.ACTION_UP) {wheelParticleA.setAngularVelocity(0);wheelParticleB.setAngularVelocity(0);} return super.onTouchEvent(event); } @Overridepublic boolean onKeyDown(int keyCode, KeyEvent event){switch (keyCode){case KeyEvent.KEYCODE_BACK: android.os.Process.killProcess(android.os.Process.myPid());break;case KeyEvent.KEYCODE_DPAD_UP://moveFlag = 1;break;case KeyEvent.KEYCODE_DPAD_DOWN: //moveFlag = 2;break;case KeyEvent.KEYCODE_DPAD_LEFT: //moveFlag = 3;wheelParticleA.setAngularVelocity(-keySpeed);wheelParticleB.setAngularVelocity(-keySpeed);break;case KeyEvent.KEYCODE_DPAD_RIGHT://moveFlag = 4;wheelParticleA.setAngularVelocity(keySpeed);wheelParticleB.setAngularVelocity(keySpeed);break;}return super.onKeyDown(keyCode, event);}@Overridepublic boolean onKeyUp(int keyCode, KeyEvent event){//moveFlag = 0;wheelParticleA.setAngularVelocity(0);wheelParticleB.setAngularVelocity(0);return super.onKeyUp(keyCode, event);} protected void onDraw(Canvas canvas) {super.onDraw(canvas);} public void run() { boolean bStop = false; Log.v("Thread1)", "is Running");while(!bStop){ // 获取画布 mCanvas = mSurfaceHolder.lockCanvas(); // 缩小到2/3大小,J2SE移植过来时太大没有改变,直接缩放Canvas mCanvas.scale(2f/3, 2f/3); // 清屏 ClearScreen(mCanvas); // 更新计算物理世界的数据 UpdateWorld(mCanvas); PaintWorld(mCanvas); PaintFps(mCanvas); // 锁帧// try { // Thread.sleep(SPEED);// } // catch (InterruptedException e) // {// }//解锁画布,提交画好的图像mSurfaceHolder.unlockCanvasAndPost(mCanvas);} } public void PaintWorld(Canvas canvas) {APEngine.setDefaultContatiner(canvas);for (int i = 0; i < paintQueue.size(); i++) {//TG TODO need to write code that determined the type of objects and sets their method. if (paintQueue.get(i) instanceof RectangleParticle) ((RectangleParticle)paintQueue.get(i)).paint();else if (paintQueue.get(i) instanceof CircleParticle) ((CircleParticle)paintQueue.get(i)).paint();else if (paintQueue.get(i) instanceof SpringConstraint) ((SpringConstraint)paintQueue.get(i)).paint();}}//end of funcpublic void UpdateWorld(Canvas canvas) {APEngine.step();rotatingRect.setRotation(rotatingRect.getRotation() + 0.03);}//end of func public void ClearScreen(Canvas canvas){//清屏 canvas.drawColor(Color.WHITE);}/** * 计算显示帧速 * @param canvas */public void PaintFps(Canvas canvas) {mLoopCount += 1;mNowTime = System.currentTimeMillis();if ((mNowTime - mFPSShowTime)>=1000) {mFPS = (float)(mLoopCount*10000/(mNowTime-mFPSShowTime))/10;mLoopCount = 0;mFPSShowTime = mNowTime;}//XDebug.Print("XGameView", "PaintFPS");canvas.drawText(String.valueOf(mFPS)+" FPS", 100, 20, mFPSPaint);}//end of func }//end of class?
?
缺点:?是不支持多边形
1 楼 lifegame2008 2011-09-16 我在公司的机器上,三星的V210,1GH主频,2.3.3的系统,能跑43帧。 2 楼 xieyu1232001 2011-10-18 我的G10可以跑40帧每秒