`
CrackRen
  • 浏览: 167974 次
  • 性别: Icon_minigender_1
  • 来自: 西安
社区版块
存档分类
最新评论

Android 物理引擎使用(1)---APEngine

阅读更多

 

APE(Actionscript Physics Engine) 是一个 ActionScript3 写成的物理引擎,用于模拟现实中物体发生的运动和碰撞。它是免费、开源的,遵循 MIT 协议。很适合做简单的物理游戏.

现提供了 Alpha, Java Port, C++ SDL Ports 三个版本 .

 

这里我把官网上的一个Demo移植到了Android上,模拟器上的帧率是5帧左右,真机在HTC Magic G2 上测试也只是6,7帧的样子.我把代码上传上来大家看看能不能优化,还有如果有真机的话希望把在你机子上运行的速度和真机的配置说一下,比较一下各类机器的差异.

 

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 example
		APEngine.setCollisionResponseMode(APEngine.SELECTIVE);
		
		// gravity -- particles of varying masses are affected the same
		APEngine.addMasslessForce(new Vector(0,3));
						
		// surfaces
		RectangleParticle 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);
		
		// 旋转矩形rotator
		rotatingRect = 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);
		
		// bridge
		CircleParticle 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 boxes
		for (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 them
		when necessary. Alternatively you can keep track of them yourself by manually adding
		them to your own lists.
		*/
		paintQueue = APEngine.getAll();
	}//end of func
	
	public 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);  
    }  
	
	@Override
	public 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);
	}

	@Override
	public 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 func
		
	public 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
 

参考:

官方网站: http://www.cove.org/ape/  

官方API: http://www.cove.org/ape/docs/api/

官方SVN: http://ape.googlecode.com/svn/

中文API参考: http://wenku.baidu.com/view/193e97cfa1c7aa00b52acb47.html

官方提供了两个Demo

Demo1: http://www.cove.org/ape/demo1.htm


Demo2: http://www.cove.org/ape/demo2.htm


APEngine

优点: 简单易用,文件很少很适合学习阅读

缺点: 是不支持多边形

 

  • 大小: 14.2 KB
  • 大小: 10.2 KB
  • 大小: 50.4 KB
分享到:
评论
1 楼 解老毕 2011-08-04  
非常谢谢 

相关推荐

Global site tag (gtag.js) - Google Analytics