Android--碰撞效果--JBox2d实现

来源:互联网 发布:桌面录屏软件 编辑:程序博客网 时间:2024/06/17 23:08

效果如下:录制的时候有点卡,实际没有卡顿哈。(基于JBox2d 2.3开发的)



代码结构:



代码:


package com.bmob.im.demo.mobaianimation.widget;import android.view.View;import com.bmob.im.demo.mobaianimation.R;import org.jbox2d.collision.shapes.CircleShape;import org.jbox2d.collision.shapes.PolygonShape;import org.jbox2d.collision.shapes.Shape;import org.jbox2d.common.Vec2;import org.jbox2d.dynamics.Body;import org.jbox2d.dynamics.BodyDef;import org.jbox2d.dynamics.BodyType;import org.jbox2d.dynamics.FixtureDef;import org.jbox2d.dynamics.World;import java.util.Random;/**jbox2d 2.3.1 * Created by Administrator--沈斌 on 2017/10/23. */public class JboxImp {    private static final String TAG = JboxImp.class.getSimpleName();    private World mWorld;    private float dt = 1f/ 30f;  //运动的频率    private int mVelocityIterations = 5;  //每一帧迭代次数    private int mPosiontionIterations = 20;  //每一帧计算的位置点    private  int mWidth,mHeight;   //刚体的边界,宽高    private float mDesity = 0.5f;  //刚体密度    private float mRatio = 20;   //坐标比率,模拟和真实的映射比率,碰撞的速度以及幅度    private final Random mRandom = new Random(); //随机数    /**     * 设置密度     * @param desity     */    public JboxImp(float desity){        this.mDesity = desity;    }    /**     * 设置边界(弹力墙的边界)     * @param width     * @param height     */    public void setWorldSize(int width,int height){        this.mWidth = width;        this.mHeight = height;    }    public void createWorld(){        if (mWorld == null){            mWorld = new World(new Vec2(0,10.0f));            updateVerticalBounds();            updateHorzontalBounds();        }    }    /**     * 竖直方向的弹力墙(上和下)     */    private void updateVerticalBounds(){        //创建静态刚体        BodyDef bodyDef = new BodyDef();        bodyDef.type = BodyType.STATIC;  //静态        PolygonShape box = new PolygonShape();        float boxWidth = switchPositionToBody(mWidth);        float boxHeight = 1;  //因为垂直,所以高度为1        box.setAsBox(boxWidth,boxHeight);        FixtureDef fixtureDef = new FixtureDef();        fixtureDef.shape = box;        fixtureDef.density = mDesity;        fixtureDef.friction = 0.8f;  //摩擦系数        fixtureDef.restitution = 0.5f;  //补偿系数        //底部body        bodyDef.position.set(0,-boxHeight);  //底部弹力墙        Body bottomBody = mWorld.createBody(bodyDef);        bottomBody.createFixture(fixtureDef);        //顶部body        bodyDef.position.set(0,switchPositionToBody(mHeight)+boxHeight);  //顶部弹力墙        Body topBody = mWorld.createBody(bodyDef);        topBody.createFixture(fixtureDef);    }    /**     * 水平方向的弹力墙(左边和右边)     */    private void updateHorzontalBounds(){        //创建静态刚体        BodyDef bodyDef = new BodyDef();        bodyDef.type = BodyType.STATIC;  //静态        PolygonShape box = new PolygonShape();        float boxWidth = 1;        float boxHeight = switchPositionToBody(mHeight);  //因为垂直,所以高度为1        box.setAsBox(boxWidth,boxHeight);        FixtureDef fixtureDef = new FixtureDef();        fixtureDef.shape = box;        fixtureDef.density = mDesity;        fixtureDef.friction = 0.8f;  //摩擦系数        fixtureDef.restitution = 0.5f;  //补偿系数        //左边body        bodyDef.position.set(-boxWidth,0);  //左边弹力墙        Body leftBody = mWorld.createBody(bodyDef);        leftBody.createFixture(fixtureDef);        //右边body        bodyDef.position.set(switchPositionToBody(mWidth)+boxWidth,0);  //右边弹力墙        Body rightBody = mWorld.createBody(bodyDef);        rightBody.createFixture(fixtureDef);    }    /**     * view坐标映射为物理的坐标     * @param viewPosition     * @return     */    public float switchPositionToBody(float viewPosition){        return viewPosition / mRatio;    }    /**     * 物理坐标映射为view的坐标     * @param bodyPosition     * @return     */    public float switchPositionToView(float bodyPosition){        return bodyPosition * mRatio;    }    public float radiansToDegrees(float radians) {        return radians / 3.14f * 180f;    }    public boolean isBodyView(View view){        Body body = (Body) view.getTag(R.id.shenbin_body_view_tag);        return body != null;    }    /**     * 创建模拟事件的刚体(运动的小圆球)     * @param view     */    public void createBody(View view){        //创建动态刚体        BodyDef bodyDef = new BodyDef();        bodyDef.type = BodyType.DYNAMIC;  //动态        Shape shape = null;        boolean isCircle = (boolean) view.getTag(R.id.shenbin_circle_view_tag);        bodyDef.position.set(switchPositionToBody(view.getX() + view.getWidth() / 2), switchPositionToBody(view.getY() + view.getHeight() / 2));        if(isCircle){            shape = createCircleShape(switchPositionToBody(view.getWidth()/2));        }        FixtureDef fixtureDef = new FixtureDef();        fixtureDef.shape = shape;        fixtureDef.density = mDesity;        fixtureDef.friction = 0.8f;  //摩擦系数        fixtureDef.restitution = 0.5f;  //补偿系数        Body body = mWorld.createBody(bodyDef);        body.createFixture(fixtureDef);        view.setTag(R.id.shenbin_body_view_tag,body);        //线性加速约束        body.setLinearVelocity(new Vec2(mRandom.nextFloat(),mRandom.nextFloat()));    }    /**     * 得到圆形刚体     * @param radius     * @return     */    private Shape createCircleShape(float radius){        CircleShape circleShape = new CircleShape();        circleShape.setRadius(radius);        return circleShape;    }    public void startWorld(){        if(mWorld != null){            mWorld.step(dt,mVelocityIterations,mPosiontionIterations);        }    }    /**     * 通过调用这个方法,使刚体运动起来     * @param x     * @param y     * @param view     */    public void applyLinearImpulse(float x ,float y,View view){        Body body = (Body) view.getTag(R.id.shenbin_body_view_tag);        Vec2 impluse = new Vec2(x,y);   //这两个参数,可以控制刚体碰撞的范围        body.applyLinearImpulse(impluse,body.getPosition(),true);    }}



package com.bmob.im.demo.mobaianimation.widget;import android.content.Context;import android.graphics.Canvas;import android.util.AttributeSet;import android.view.View;import android.widget.FrameLayout;import com.bmob.im.demo.mobaianimation.R;import org.jbox2d.dynamics.Body;/** * Created by Administrator--沈斌 on 2017/10/23. */public class CollisionView extends FrameLayout {    private JboxImp jboxImp;    public CollisionView(Context context) {        this(context, null);    }    public CollisionView(Context context, AttributeSet attrs) {        this(context, attrs, 0);    }    public CollisionView(Context context, AttributeSet attrs, int defStyleAttr) {        super(context, attrs, defStyleAttr);        setWillNotDraw(false);        initView();    }    private void initView(){        jboxImp = new JboxImp(getResources().getDisplayMetrics().density);    }    @Override    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {        super.onLayout(changed, left, top, right, bottom);        jboxImp.createWorld();        int childCount = getChildCount();        for (int i = 0; i < childCount; i++) {            View view = getChildAt(i);            Body body = (Body) view.getTag(R.id.shenbin_body_view_tag);            if(body == null || changed){                jboxImp.createBody(view);            }        }    }    @Override    protected void onDraw(Canvas canvas) {        super.onDraw(canvas);        jboxImp.startWorld();//也可以放到onLayout里面        int childCount = getChildCount();        for (int i = 0; i < childCount; i++) {            View view = getChildAt(i);            Body body = (Body) view.getTag(R.id.shenbin_body_view_tag);            if(view != null && jboxImp.isBodyView(view)){                view.setX(jboxImp.switchPositionToView(body.getPosition().x) - view.getWidth() / 2);                view.setY(jboxImp.switchPositionToView(body.getPosition().y) - view.getHeight() / 2);                view.setRotation(jboxImp.radiansToDegrees(body.getAngle() % 360));            }        }        invalidate();    }    public void onSensorChanged(float x,float y){        int childCount = getChildCount();        for (int i = 0; i < childCount; i++) {            View view = getChildAt(i);            if(view != null && jboxImp.isBodyView(view)){                jboxImp.applyLinearImpulse(x,y,view);            }        }    }    @Override    protected void onSizeChanged(int w, int h, int oldw, int oldh) {        super.onSizeChanged(w, h, oldw, oldh);        jboxImp.setWorldSize(w,h);    }}



package com.bmob.im.demo.mobaianimation;import android.app.Activity;import android.content.Context;import android.hardware.Sensor;import android.hardware.SensorEvent;import android.hardware.SensorEventListener;import android.hardware.SensorManager;import android.os.Bundle;import android.view.Gravity;import android.widget.FrameLayout;import android.widget.ImageView;import com.bmob.im.demo.mobaianimation.widget.CollisionView;import java.util.Random;public class MainActivity extends Activity implements SensorEventListener{    CollisionView myView;    private SensorManager sensorManager;    private  int[] imgs = {            R.drawable.share_fb,            R.drawable.share_kongjian,            R.drawable.share_pyq,            R.drawable.share_qq,            R.drawable.share_tw,            R.drawable.share_wechat,            R.drawable.share_weibo,            R.mipmap.ic_launcher    };    private Sensor defaultSensor;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);    }    @Override    public void onContentChanged() {        super.onContentChanged();        sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);        defaultSensor = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);        myView = (CollisionView) findViewById(R.id.myView);        initViews();    }    @Override    protected void onResume() {        super.onResume();        sensorManager.registerListener( this,defaultSensor,SensorManager.SENSOR_DELAY_UI);    }    @Override    protected void onPause() {        super.onPause();        sensorManager.unregisterListener(this);    }    private void initViews() {        FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.WRAP_CONTENT, FrameLayout.LayoutParams.WRAP_CONTENT);        layoutParams.gravity = Gravity.CENTER;        for(int i = 0; i < imgs.length  ; i ++){            ImageView imageView = new ImageView(this);            imageView.setImageResource(imgs[i]);            imageView.setTag(R.id.shenbin_circle_view_tag,true);            myView.addView(imageView,layoutParams);        }    }    private final Random mRandom = new Random();    /**     * 使用传感器,因为这个会一直回调,一直运行,所以可以使刚体不停的碰撞。     * @param sensorEvent     */    @Override    public void onSensorChanged(SensorEvent sensorEvent) {        if(sensorEvent.sensor.getType() == Sensor.TYPE_ACCELEROMETER){            float x = sensorEvent.values[0];            float y = sensorEvent.values[1] * 2.0f;            myView.onSensorChanged(mRandom.nextInt(200) - 100, mRandom.nextInt(1000) - 500);  //这两个参数传递下去,可以控制刚体碰撞的范围        }    }    @Override    public void onAccuracyChanged(Sensor sensor, int i) {    }}


<?xml version="1.0" encoding="utf-8"?><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"    android:background="@color/colorAccent"    tools:context="com.bmob.im.demo.mobaianimation.MainActivity">    <com.bmob.im.demo.mobaianimation.widget.CollisionView        android:layout_width="match_parent"        android:layout_height="300dp"        android:id="@+id/myView"        android:background="#fff"/></RelativeLayout>



原创粉丝点击