SeniorUI34_jbox2d引擎实现重力碰撞效果

SeniorUI_高级UI汇总目录
SeniorUI34_maven项目生成java的两种方法

1 效果图

在这里插入图片描述

2 需求

实现一群圆形物体重力环境下 掉落、碰撞运动效果

3 分析

  • 引进jbox库,实现运动碰撞效果
  • 自定义一个ViewGroup,所有物体即它的childView在这里面运动,
  • 定义一个jbox API下的控制实现类JboxImpl,是对现实世界即ViewGroup的映射
  • 将ViewGroup的参数传到JboxImpl中,创建世界的边缘,确定四周不能动的边框-刚体
  • 将ViewGrope的child映射到JboxImpl中,创建不同的可以移动的Body
  • 监听重力感应,将感应的参数通过ViewGroup传到JboxImpl世界中,从而获取对应每个刚体的的坐标
  • 将坐标设置到对应tag的View中去,通知ViewGroup重绘

4 主要代码

JboxImpl

public class JboxImpl {

    private static final String TAG = "tim@" + JboxImpl.class.getSimpleName();

    private World mWorld; //模拟世界
    private float dt = 1f/60f; //模拟世界的频率
    private int mVelocityIterations = 5; //速率迭代器
    private int mPosiontIterations = 20; //迭代次数

    private int mWidth,mHeight;

    private float mDesity = 0.5f;
    private float mRatio = 50;//坐标映射比例
    private final Random mRandom = new Random();

    public JboxImpl(float desity) {
        mDesity = desity;
    }

    public void setWorlSize(int width, int height) {
        mHeight = height;
        mWidth = width;
    }

    public void startWorld() {
        if (mWorld != null) {
            mWorld.step(dt, mVelocityIterations, mPosiontIterations);
        }
    }

    public void createWorld() {
        if (mWorld == null) {
            mWorld = new World(new Vec2(0, 10.0f));
            updateVertiacalBounds();
            updateHorizontalBounds();
        }
    }

    public void creatBody(View view) {
        BodyDef bodyDef = new BodyDef();
        bodyDef.setType(BodyType.DYNAMIC);

        bodyDef.position.set(switchPositionToBody( view.getX() + (view.getWidth() / 2) )
                ,switchPositionToBody(view.getY() + (view.getHeight() / 2))  );

        Shape shape = null;
        Boolean isCircle = (Boolean) view.getTag(R.id.dn_view_circle_tag);
        if (isCircle != null && isCircle) {
            shape = craeteCircleShape( switchPositionToBody(view.getWidth() / 2) );
        } else {
            Log.i(TAG,"createBody veiw tag is not circle!!!");
            return;
        }
        FixtureDef fixtureDef = new FixtureDef();
        fixtureDef.setShape(shape);
        fixtureDef.friction = 0.8f;//摩擦系数
        fixtureDef.density = mDesity;
        fixtureDef.restitution = 0.5f;//补偿系数

        Body body = mWorld.createBody(bodyDef);
        body.createFixture(fixtureDef);
        view.setTag(R.id.dn_view_body_tag, body);

        body.setLinearVelocity(new Vec2(mRandom.nextFloat(), mRandom.nextFloat()));

    }

    //创建圆形
    private Shape craeteCircleShape(float radius) {
        CircleShape circleShape = new CircleShape();
        circleShape.setRadius(radius);
        return circleShape;
    }

    private void updateVertiacalBounds() {
        BodyDef bodyDef = new BodyDef();
        bodyDef.type = BodyType.STATIC; //定义静止的刚体

        PolygonShape box = new PolygonShape(); //定义的形状
        float boxWidth = switchPositionToBody(mWidth);
        float boxHeight = switchPositionToBody(mRatio);
        box.setAsBox(boxWidth, boxHeight); //确定为矩形

        FixtureDef fixtureDef = new FixtureDef();
        fixtureDef.shape = box;
        fixtureDef.density = mDesity;
        fixtureDef.friction = 0.8f;//摩擦系数
        fixtureDef.restitution = 0.5f; //补偿系数

        bodyDef.position.set(0, -boxHeight);
        Body topBody = mWorld.createBody(bodyDef); //创建一个真实的上边 body
        topBody.createFixture(fixtureDef);

        bodyDef.position.set(0, switchPositionToBody(mHeight) + boxHeight);
        Body bottomBody = mWorld.createBody(bodyDef);
        bottomBody.createFixture(fixtureDef);
    }

    private void updateHorizontalBounds() {
        BodyDef bodyDef = new BodyDef();
        bodyDef.type = BodyType.STATIC; //定义静止的刚体

        PolygonShape box = new PolygonShape(); //定义的形状
        float boxWidth = switchPositionToBody(mRatio);
        float boxHeight = switchPositionToBody(mHeight);
        box.setAsBox(boxWidth, boxHeight); //确定为矩形

        FixtureDef fixtureDef = new FixtureDef();
        fixtureDef.shape = box;
        fixtureDef.density = mDesity;
        fixtureDef.friction = 0.8f;//摩擦系数
        fixtureDef.restitution = 0.5f; //补偿系数

        bodyDef.position.set(-boxWidth, 0);
        Body leftBody = mWorld.createBody(bodyDef); //创建一个真实的上边 body
        leftBody.createFixture(fixtureDef);

        bodyDef.position.set(switchPositionToBody(mWidth) + boxWidth, 0);
        Body rightBody = mWorld.createBody(bodyDef);
        rightBody.createFixture(fixtureDef);
    }

    //view坐标映射为物理的坐标
    private float switchPositionToBody(float viewPosition) {
        return viewPosition / mRatio;
    }

    //物理的坐标映射为iew坐标映射
    private float switchPositionToView(float bodyPosition) {
        return bodyPosition * mRatio;
    }

    public boolean isBodyView(View view) {
        Body body = (Body) view.getTag(R.id.dn_view_body_tag);
        return body != null;

    }

    public float getViewX(View view) {
        Body body = (Body) view.getTag(R.id.dn_view_body_tag);
        if (body != null) {
            return switchPositionToView(body.getPosition().x ) - (view.getWidth() / 2);
        }
        return 0;
    }

    public float getViewY(View view) {
        Body body = (Body) view.getTag(R.id.dn_view_body_tag);
        if (body != null) {
            return switchPositionToView(body.getPosition().y ) - (view.getHeight() / 2);
        }
        return 0;
    }

    public float getViewRotaion(View view) {
        Body body = (Body) view.getTag(R.id.dn_view_body_tag);
        if (body != null) {
            float angle = body.getAngle();
            return  (angle / 3.14f * 180f) % 360;
        }
        return 0;
    }

    public void applyLinearImpulse(float x, float y, View view) {
        Body body = (Body) view.getTag(R.id.dn_view_body_tag);
        Vec2 impluse = new Vec2(x,y);
        body.applyLinearImpulse(impluse, body.getPosition(), true); //给body做线性运动 true 运动完之后停止
    }


}

CollisionView

public class CollisionView extends FrameLayout{
    private JboxImpl jboxImpl;
    public CollisionView(@NonNull Context context) {
        this(context,null);
    }

    public CollisionView(@NonNull Context context, @Nullable AttributeSet attrs) {
        this(context, attrs,0);
    }

    public CollisionView(@NonNull Context context, @Nullable AttributeSet attrs, @AttrRes int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        setWillNotDraw(false);
        initView();
    }

    private void initView() {
        jboxImpl = new JboxImpl(getResources().getDisplayMetrics().density);
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        jboxImpl.setWorlSize(w,h);
    }

    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        super.onLayout(changed, left, top, right, bottom);
        jboxImpl.createWorld();
        //子viwe创建tag 设置body
        int childCount = getChildCount();
        for (int i =0; i< childCount; i++) {
            View view = getChildAt(i);
            if (!jboxImpl.isBodyView(view) || changed) {
                jboxImpl.creatBody(view);
            }
        }
    }

    @Override
    protected void onDraw(Canvas canvas) {
        jboxImpl.startWorld();
        int childCount = getChildCount();
        for (int i =0; i< childCount; i++) {
            View view = getChildAt(i);
            if (jboxImpl.isBodyView(view)) {
               view.setX(jboxImpl.getViewX(view));
                view.setY(jboxImpl.getViewY(view));
                view.setRotation(jboxImpl.getViewRotaion(view));
            }
        }
        invalidate();
    }

    public void onSensorChanged(float x, float y) {
        int childCount = getChildCount();
        for (int i =0; i< childCount; i++) {
            View view = getChildAt(i);
            if (jboxImpl.isBodyView(view)) {
                jboxImpl.applyLinearImpulse(x,y,view);
            }
        }
    }
}

使用:JboxActivity

public class JboxActivity extends FragmentActivity implements SensorEventListener {


    private SensorManager sensorManager;
    private Sensor defaultSensor;
    private CollisionView collisionView;

    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
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.jbox_activity);
    }

    @Override
    protected void onResume() {
        super.onResume();
        sensorManager.registerListener(this, defaultSensor, SensorManager.SENSOR_DELAY_UI);
    }

    @Override
    protected void onPause() {
        super.onPause();
        sensorManager.unregisterListener(this);
    }


    @Override
    public void onContentChanged() {
        collisionView = (CollisionView) findViewById(R.id.jbox_view);
        initView();
        sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
        defaultSensor = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);

    }

    private void initView() {
        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.dn_view_circle_tag, true);
            collisionView.addView(imageView,layoutParams);
        }
    }

    @Override
    public void onSensorChanged(SensorEvent event) {
        if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
            float x = event.values[0];
            float y = event.values[1] * 2.0f;
            collisionView.onSensorChanged(-x, y);
        }
    }

    @Override
    public void onAccuracyChanged(Sensor sensor, int accuracy) {

    }
}

5 Demo

JboxActivity

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值