Box2D Forums

It is currently Sun May 19, 2013 4:01 pm

All times are UTC - 8 hours [ DST ]




Post new topic Reply to topic  [ 3 posts ] 
Author Message
PostPosted: Thu Apr 19, 2012 3:59 am 
Offline

Joined: Thu Apr 19, 2012 3:45 am
Posts: 3
First off, I love this project! I've always wanted to run a good simulation.

Recently, I have tried to port the jbox2d 2.1.2.2 version to the Android device. I updated from the 2.0.1 version once I had finished a tutorial. The 2.1.2.2 jbox2d crashes on android without fail.

Opening the debugger, I found that the error was caused after the world creation,
Code:
world = new World(gravity, doSleep);
was called. The debugger then went to the logger "slf4j" and crashed after its block. I then reverted to the 2.1.2.0 version of jbox2d, but the crash remained.

Googling the problem, I found this fix. To summarize, the slf4j logger was removed from the 2.1.2 jar file and the 1.6.3 version of slf4j jar was added to the project. The issue was fixed for me after this solution.

So, to whomever runs the jbox2d svn (toucansam?), please investigate this fix and have it committed. Running box2d at the latest revision is essential to using the tutorials and threads found on this forum. Thank you.

Both of the following classes run on Android 2.2 and jbox2d 2.1.2.0 with the solution outlined above.

World creation
Code:
package com.radix.turtle;

import org.jbox2d.callbacks.ContactImpulse;
import org.jbox2d.callbacks.ContactListener;
import org.jbox2d.collision.Manifold;
import org.jbox2d.collision.shapes.CircleShape;
import org.jbox2d.collision.shapes.PolygonShape;
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 org.jbox2d.dynamics.contacts.Contact;

public class PhysicsWorld {
   int numBalls = 120;
   public float targetFPS = 45;
   public float timeStep = (1 / targetFPS);
   private int iterations = 2;
   public Body[] bodies;
   public int count = 0;
   private World world;
   private BodyDef groundBodyDef;

   public void create() {
      // Step 1: Create Physics World Boundaries
      bodies = new Body[numBalls];
      
      // Step 2: Create Physics World with Gravity
      Vec2 gravity = new Vec2( 0, 0.0f);
      boolean doSleep = true;
      world = new World(gravity, doSleep);
      
        // Set a contact listener.
        world.setContactListener( new ContactListener()
        {
         @Override
         public void beginContact(Contact contact) {
            // TODO Auto-generated method stub
            
         }

         @Override
         public void endContact(Contact contact) {
            // TODO Auto-generated method stub
            
         }

         @Override
         public void preSolve(Contact contact, Manifold oldManifold) {
            // TODO Auto-generated method stub
            
         }

         @Override
         public void postSolve(Contact contact, ContactImpulse impulse) {
            // TODO Auto-generated method stub
            
         }
        } );
      
      // Step 3: Create Ground Box
      groundBodyDef = new BodyDef();
      groundBodyDef.position.set(new Vec2((float) 0, (float) 0));
      groundBodyDef.type = BodyType.STATIC;
      Body ground = world.createBody(groundBodyDef);
      
        // Create the fixtures (physical aspects) of the ground body.
        FixtureDef groundEdgeFixtureDef = new FixtureDef();
        groundEdgeFixtureDef.density = 1.0f;
        groundEdgeFixtureDef.friction = 1.0f;
        groundEdgeFixtureDef.restitution = 0.4f;

        PolygonShape groundEdge = new PolygonShape();
        groundEdgeFixtureDef.shape = groundEdge;
       
        groundEdge.setAsBox(2000.0f, 1.0f);
        ground.createFixture( groundEdgeFixtureDef );
       
       
        //left wall
        groundBodyDef.position.set(new Vec2((float) -20, (float) 0));
        Body ground2 = world.createBody(groundBodyDef);
        groundEdge.setAsBox(1.0f, 2000.0f);
        ground2.createFixture( groundEdgeFixtureDef );
       
        //right wall
        groundBodyDef.position.set(new Vec2((float) 20, (float) 0));
        Body ground3 = world.createBody(groundBodyDef);
        groundEdge.setAsBox(1.0f, 2000.0f);
        ground3.createFixture( groundEdgeFixtureDef );
       
        //top wall
        groundBodyDef.position.set(new Vec2((float) 0, (float) 35));
        Body ground4 = world.createBody(groundBodyDef);
        groundEdge.setAsBox(2000.0f, 1.0f);
        ground4.createFixture( groundEdgeFixtureDef );
      
   }

   public void addBall() {
      // Create Dynamic Body
      BodyDef bodyDef = new BodyDef();
      bodyDef.type = BodyType.DYNAMIC;
      bodyDef.allowSleep=true;
      
      bodyDef.position.set((float) (count/8 + Math.random()*3), (float) (28-count*1.5));
      if (bodies == null)
         bodies = new Body[numBalls];
      
      bodies[count] = world.createBody(bodyDef);   
      bodies[count].setLinearVelocity(new Vec2( (float)(Math.random()*3), (float) (Math.random()*3)));
      
      // Create Shape with Properties
      CircleShape circle = new CircleShape();
      circle.m_radius = (float) (Math.random()*1.5+0.5);
      
      // Assign fixture to Body      
        FixtureDef ballFixtureDef = new FixtureDef();
        ballFixtureDef.density = 1.0f; // Must have a density or else it won't
                                       // be affected by gravity.
        ballFixtureDef.restitution = 0.9f; // Define how bouncy the ball is.
        ballFixtureDef.friction = 0.2f;
        ballFixtureDef.shape = circle;

        // Add the fixture to the ball body.
        bodies[count].createFixture( ballFixtureDef );
      // Increase Counter
      
      
      count += 1;
   }
   
   public void addBallPosVel(float Xcoord, float Ycoord, float Xvel, float Yvel) {
      // Create Dynamic Body
      BodyDef bodyDef = new BodyDef();
      bodyDef.type = BodyType.DYNAMIC;
      bodyDef.allowSleep=true;
      
      bodyDef.position.set((float) (Xcoord), Ycoord);
      if (bodies == null)
         bodies = new Body[numBalls];
      
      bodies[count] = world.createBody(bodyDef);   
      bodies[count].setLinearVelocity(new Vec2(Xvel, Yvel));
      
      // Create Shape with Properties
      CircleShape circle = new CircleShape();
      circle.m_radius = (float) (Math.random()*0.9+0.2);
      
      // Assign fixture to Body      
        FixtureDef ballFixtureDef = new FixtureDef();
        ballFixtureDef.density = 1.0f; // Must have a density or else it won't
                                       // be affected by gravity.
        ballFixtureDef.restitution = 0.9f; // Define how bouncy the ball is.
        ballFixtureDef.friction = 0.2f;
        ballFixtureDef.shape = circle;

        // Add the fixture to the ball body.
        bodies[count].createFixture( ballFixtureDef );
      // Increase Counter
      
      
      count += 1;
      
   }

   public void update() {
      // Update Physics World
      world.step(timeStep, iterations, iterations);
   }
   
}



Drawing to canvas

Code:
package com.radix.turtle;

import org.jbox2d.common.Vec2;
import org.jbox2d.dynamics.Body;

import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Paint.Align;
import android.util.Log;
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
import android.view.GestureDetector;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.View.OnTouchListener;
import android.view.Window;
import android.view.WindowManager;
 
public class PhysicsTest extends Activity implements OnTouchListener{
    PhysicsWorld mWorld;
    private Handler mHandler;
    private Body[] bodies;
   
    int numBallsForRender = 5;
    float tStep,bY ,bX, pointerX, pointerY, initialX, initialY;
    float screenCenterX, screenCenterY;
    float pixelsPerMeter = 30.0f, metersPerPixel = 1.0f/pixelsPerMeter;
    float simX, simY;
   
   NauteSurface ourSurfaceView;
   float canvasW, canvasH, kH, kW, kHW, midCanvasY, midCanvasX;
   
   Paint debugPaint,circlePaint, numberPaint;
   Vec2 position;

   boolean firstRun, nextBallIsBullet;
   
   private ScaleGestureDetector mScaleDetector;
   GestureDetector gestures;
   private float mScaleFactor = 0.4f;
 
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
      ourSurfaceView = new NauteSurface(this);
      ourSurfaceView.setOnTouchListener(this);
      
      mScaleDetector = new ScaleGestureDetector(this, new ScaleListener());
      gestures = new GestureDetector(this,  new GestureListener()); 
      
      firstRun=true;
      
        mWorld = new PhysicsWorld();
        mWorld.create();
 
        // Add 50 Balls
        for (int i=0; i<numBallsForRender; i++) {
            mWorld.addBall();
        }
 
        // Start Regular Update
        mHandler = new Handler();
        mHandler.post(update);
       
      //get a fullscreen window!
      requestWindowFeature(Window.FEATURE_NO_TITLE);
      getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
      //get a fullscreen window!
      
        setContentView(ourSurfaceView);   
       

    }
 
    @Override
    protected void onPause() {
        super.onPause();
        mHandler.removeCallbacks(update);
        ourSurfaceView.pause();
        //finish();
    }
   
   @Override
   protected void onResume() {
      // TODO Auto-generated method stub
      super.onResume();
      ourSurfaceView.resume();
   }
 
    private Runnable update = new Runnable() {
       
        public void run() {
            mWorld.update();
            tStep = mWorld.timeStep;
            mHandler.postDelayed(update, (long) (tStep*1000));
            bodies = mWorld.bodies;
            numBallsForRender= mWorld.count;
        }
    };
   

   private void doGameStuff(Canvas canvas) {

      canvasW = canvas.getWidth();
      canvasH = canvas.getHeight();
      midCanvasY = canvasH/2;
      midCanvasX = canvasW/2;
      
      kH = canvasH/480; //values for developer device!
      kW = canvasW/800; //values for developer device!
      kHW = kH*kW;   
      
      debugPaint = new Paint();
      debugPaint.setColor(Color.WHITE);
      debugPaint.setTextAlign(Align.LEFT);
      debugPaint.setTextSize(20);
      //debugPaint.setTypeface(Typeface.DEFAULT_BOLD);
      debugPaint.setAntiAlias(true);   
      
      numberPaint = new Paint();
      numberPaint.setColor(Color.RED);
      numberPaint.setTextAlign(Align.LEFT);
      numberPaint.setTextSize(15);
      numberPaint.setAntiAlias(true);   
      
      circlePaint = new Paint();
      circlePaint.setColor(Color.WHITE);
      circlePaint.setAntiAlias(true);   
   }


   @Override
   public boolean onTouch(View v, MotionEvent event) {
      // TODO Auto-generated method stub
      mScaleDetector.onTouchEvent(event);
      gestures.onTouchEvent(event);
      switch(event.getAction()){
      
         case MotionEvent.ACTION_DOWN:
            initialX = event.getX();
            initialY = event.getY();
            
         break;
         
         case MotionEvent.ACTION_MOVE:
            
            break;
      
         case MotionEvent.ACTION_UP:
            pointerX = event.getX();
            pointerY = event.getY();
            
            if (  Math.abs(initialX-pointerX)<2 && Math.abs(initialY-pointerY)<2 ) {
               simX = (pointerX - midCanvasX)/mScaleFactor + screenCenterX;//real pixel coord of touch
               simY = (pointerY - midCanvasY)/mScaleFactor + screenCenterY;
               
               simX = P2M( simX );
               simY = P2M(canvasH-simY);
               
               if (nextBallIsBullet==true){
                  nextBallIsBullet=false;
                  mWorld.addBallPosVel(simX, simY, 0, -128.0f );
               } else {
                  mWorld.addBallPosVel(simX, simY, (float)(16.0*(Math.random()-0.5)), (float)(16.0*(Math.random()-0.5)) );
               }
               
            } else {
               //ENTER THE SCREEN SCROLL DAWG
               
            }
            break;
            
         }
      
      return true;
   }
   
   private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener {
       @Override
       public boolean onScale(ScaleGestureDetector detector) {
           mScaleFactor *= detector.getScaleFactor();
          
           // Don't let the object get too small or too large.
           mScaleFactor = Math.max(0.1f, Math.min(mScaleFactor, 7.0f));

           return true;
       }
   }
   
   private class GestureListener implements GestureDetector.OnGestureListener,  GestureDetector.OnDoubleTapListener {

            @Override
            public boolean onDoubleTap(MotionEvent e) {
               // TODO Auto-generated method stub
               return false;
            }
      
            @Override
            public boolean onDoubleTapEvent(MotionEvent e) {
               // TODO Auto-generated method stub
               return false;
            }
      
            @Override
            public boolean onSingleTapConfirmed(MotionEvent e) {
               // TODO Auto-generated method stub
               return false;
            }
      
            @Override
            public boolean onDown(MotionEvent e) {
               // TODO Auto-generated method stub
               return false;
            }
      
            @Override
            public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
                  float velocityY) {
               // TODO Auto-generated method stub
               return false;
            }
      
            @Override
            public void onLongPress(MotionEvent e) {
               // TODO Auto-generated method stub
               nextBallIsBullet=true;
               
            }
      
            @Override
            public boolean onScroll(MotionEvent e1, MotionEvent e2,
                  float distanceX, float distanceY) {
               // TODO Auto-generated method stub
               float k = 1.0f;
               screenCenterX+= k*distanceX/mScaleFactor;
               screenCenterY+= k*distanceY/mScaleFactor;
               return true;
            }
      
            @Override
            public void onShowPress(MotionEvent e) {
               // TODO Auto-generated method stub
               
            }
      
            @Override
            public boolean onSingleTapUp(MotionEvent e) {
         // TODO Auto-generated method stub
         return false;
      } 
 
   }
   
      private float P2M(float xPixels) {
         // TODO Auto-generated method stub
         return xPixels*metersPerPixel;
      }
   
      private float M2P(float xMetres) {
         // TODO Auto-generated method stub
         return xMetres*pixelsPerMeter;
      }
      
   
//SUPER PASTE! BELOW
public class NauteSurface extends SurfaceView implements Runnable{

      SurfaceHolder ourHolder;
      Thread ourThread = null;
      boolean isRunning = false;
      Canvas canvas;

      Body bd;
      String s = "\n", PrintStatus, s1[];
      
      
      public NauteSurface(Context context) {
         super(context);
         ourHolder = getHolder();
      }

      public void pause(){
         isRunning = false;
         
         
         while(true){
            try {
               ourThread.join();
            } catch (InterruptedException e) {
               // TODO Auto-generated catch block
               e.printStackTrace();
            }
            break;
         }
         
         ourThread = null;
         finish();

      }
      
      public void resume(){
         isRunning = true;   
         ourThread = new Thread(this);
         ourThread.start();
      }
      
      public void run() {
         // TODO Auto-generated method stub
         while(isRunning){
            if (!ourHolder.getSurface().isValid())
               continue;
               //if not a valid surface
            
            canvas = ourHolder.lockCanvas();

            if (firstRun==true){
               doGameStuff(canvas);
               firstRun=false;
            }
            
            canvas.drawRGB(0, 20, 50);
            

            
            
            //setScreenCenter(bX, bY);

            //canvas.scale(mScaleFactor, mScaleFactor ,bX, bY);
            canvas.save();
            canvas.translate(midCanvasX-screenCenterX, midCanvasY-screenCenterY);
            canvas.scale(mScaleFactor, mScaleFactor, screenCenterX, screenCenterY);

            for(int i=0; i<numBallsForRender; i++){
               bd = bodies[i];
               bX = M2P(bd.getPosition().x);
               bY = 800 - M2P(bd.getPosition().y);            
               
               canvas.drawCircle(bX, bY, M2P(bd.m_fixtureList.m_shape.m_radius)*1.06f, circlePaint);
               //canvas.drawCircle(bX, bY, 3.0f, circlePaint);
               
               if (i<16)canvas.drawText(i+"", bX, bY, numberPaint);
            }

            Body bk = bodies[1];
            bX = M2P(bk.getPosition().x);
            bY = 800 - M2P(bk.getPosition().y);
            
            if (true==true){   
               
               
               PrintStatus = ""
               +"step value: "+tStep+" or "+(1/tStep)+s
               +"ball pos+ "+bX+"  "+bY+s
               +"real ball pos+ "+bk.getPosition().x+"  "+bk.getPosition().y+s
               +"pointer pos+ "+simX+"  "+simY+s
               +"mass rendering "+numBallsForRender+" balls"+s
               +pixelsPerMeter+" pixels per meter"+s
               +"nextBallIsBullet :"+nextBallIsBullet+s
               
               
               +"RADIX 2012"+s
               ;
               
               s1 = PrintStatus.split(s);
               
               for(int i=0; i<s1.length; i++){
                  canvas.drawText(s1[i], 300, 225+25*i, debugPaint);
               }
                        
               
            }
            
            canvas.restore();
            
            ourHolder.unlockCanvasAndPost(canvas);
            
         }
         
      }





   }




   
}

//Thread.sleep( Math.max(15-(t1-t2), 0) );




Top
 Profile  
 
PostPosted: Mon Apr 23, 2012 8:13 pm 
Offline

Joined: Mon Jun 08, 2009 12:21 pm
Posts: 353
Investigated. Result:

Please don't use that custom fix. That version is deprecated and has bugs. Their issue could have been for a couple different reasons, but basically, you're using the jar without dependencies. The one that includes dependencies is right there, it's called "jbox2d-library-2.1.2.2-jar-with-dependencies.jar"...

If you don't want to use that jar, you can just use the normal "jbox2d-library-2.1.2.2.jar" and include "slf4j-api-1.6.1" (or whatever version is in the pom)


Top
 Profile  
 
PostPosted: Wed May 02, 2012 7:31 pm 
Offline

Joined: Thu Apr 19, 2012 3:45 am
Posts: 3
Works like a charm. lib 2.1.2.2 with the sljf 1.6.4 from the logger website works on android 2.2. (clarification). Thanks!


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 3 posts ] 

All times are UTC - 8 hours [ DST ]


Who is online

Users browsing this forum: No registered users and 2 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Powered by phpBB® Forum Software © phpBB Group