0
votes

I've just started with Android programming using eclipse and recently came across this problem. I have a bunch of sprites assigned to an arraylist. Now, I want to make it so that collision is detected automatically between sprites but the template I'm currently using can only detect collision between the surface's borders and the moving sprites. Each sprite's position and speed is generated randomly. How can I change the update() function in my Sprite() class to detect collision between the moving sprites themselves and at the same changing/bouncing to the opposite direction? Here's my Sprite class template:

package com.gameproject.cai_test;

import java.util.Random;


   public Sprite(GameView gameView, Bitmap bmp) {
         this.width = bmp.getWidth() / BMP_COLUMNS;
         this.height = bmp.getHeight() / BMP_ROWS;
         this.gameView = gameView;
         this.bmp = bmp;


         Random rnd = new Random();
         x = rnd.nextInt(gameView.getWidth() - width);
         y = rnd.nextInt(gameView.getHeight() - height);
         xSpeed = rnd.nextInt(MAX_SPEED * 2) - MAX_SPEED;
         ySpeed = rnd.nextInt(MAX_SPEED * 2) - MAX_SPEED;
   }

private void update() {
         if (x >= gameView.getWidth() - width - xSpeed || x + xSpeed <= 0) {
                xSpeed = -xSpeed;
         }
         x = x + xSpeed;
         if (y >= gameView.getHeight() - height - ySpeed || y + ySpeed <= 0) {
                ySpeed = -ySpeed;
         }
         y = y + ySpeed;

         currentFrame = ++currentFrame % BMP_COLUMNS;
   }

   public void onDraw(Canvas canvas) {
         update();
         int srcX = currentFrame * width;
         int srcY = getAnimationRow() * height;
         Rect src = new Rect(srcX, srcY, srcX + width, srcY + height);
         Rect dst = new Rect(x, y, x + width, y + height);

         canvas.drawBitmap(bmp, src, dst, null);
   }

   private int getAnimationRow() {
         double dirDouble = (Math.atan2(xSpeed, ySpeed) / (Math.PI / 2) + 2);
         int direction = (int) Math.round(dirDouble) % BMP_ROWS;
         return DIRECTION_TO_ANIMATION_MAP[direction];
   }


   //gameplay operations

   //only values from 0 to 9 will be picked; each assigned its own sprite in the list
   public int randomValue(){
       Random rnd = new Random();
       RandomValue = rnd.nextInt(10);
       return RandomValue; 
   }

   //sequence operation from addition, subtraction, multiplication, and division
   public int produceSum(){
       int addOne = 0;
       int addTwo = 0;
       Sum = addOne + addTwo;
       return Sum;
   }

   public int produceDiff(){
       int deductOne = 0;
       int deductTwo = 0;
       Difference = deductOne - deductTwo;
       return Difference;
   }

   public int produceProduct(){
       int multiOne = 0;
       int multiTwo = 0;
       Product = multiOne * multiTwo;
       return Product;
   }

   public int produceQuotient(){
       int divideOne = 0;
       int divideTwo = 0;
       Quotient = divideOne / divideTwo;
       return Quotient;
   }

   //each time this returns true, the game is reset with new operation
   //compares the value of the bubble picked to the random number being compared through operations
   public boolean compareBubbleValue(int randomBubble, int bubbleValue){

       if (randomBubble == bubbleValue){
           return true;
       }
       return false;
   }

}

As you can see, the update() method only checks the collision between the moving sprites and the borders.

3

3 Answers

0
votes

Okey, so lets name your array of sprites spriteArray and loop through it twice

 public Rect getBounds(){ //put this in your sprite and enemy-class.
   return new Rect(x, y, x+width, y+height);
 }

 Public void checkCollision(){
    for (int i = 0; i<spriteArray.size(); i++){
           Rect mySprite = spriteArray.get(i).getBounds(); //create rect for every sprite in array
             for (int j = 0; j<spriteArray.size(); i++){
                Rect myOtherSprite = spriteArray.get(i).getBounds();
                  if(mySprite.intersect(myOtherSprite)){ //check if they touch
                   //Todo code here
             }
          }
      }
  }

then you just put this method in your update-method.

0
votes

Here's the coding for the GameView class (pardon the mess, it's a jumble of codes and comments):

package com.gameproject.cai_test;


public class GameView extends SurfaceView {
   private Bitmap bmp;
   private Bitmap background;
   private Bitmap backgroundImage;
   private Bitmap pop;
   private SurfaceHolder holder;
   private GameLoopThread gameLoopThread;
   private List<Sprite> sprites = new ArrayList<Sprite>();
   private List<TempSprite> temps = new ArrayList<TempSprite>();
   private int[] bubbleValue = {0,1,2,3,4,5,6,7,8,9,10};
   private long lastClick;
   private SpriteObject timer;
   private SpriteObject morebanner;
   private SpriteObject formulaBox;
   private SpriteObject levelbanner1;
   private SurfaceHolder surfaceHolder;


   public GameView(Context context) {
         super(context);
         gameLoopThread = new GameLoopThread(this);
         timer = new SpriteObject (BitmapFactory.decodeResource(getResources(), R.drawable.hourglass), 1200, 100);
         morebanner = new SpriteObject(BitmapFactory.decodeResource(getResources(), R.drawable.morebanner), 650, 300);
         formulaBox = new SpriteObject(BitmapFactory.decodeResource(getResources(), R.drawable.formulabox), 650, 600);
         background = BitmapFactory.decodeResource(getResources(), R.drawable.background);
         backgroundImage = BitmapFactory.decodeResource(getResources(), R.drawable.background);
         pop = BitmapFactory.decodeResource(getResources(), R.drawable.pop);
         final Toast toast1 = Toast.makeText(context, "LEVEL 1 start", Toast.LENGTH_LONG);
         holder = getHolder();
         holder.addCallback(new Callback() {

                @Override
                public void surfaceDestroyed(SurfaceHolder holder) {
                }

                @Override
                public void surfaceCreated(SurfaceHolder holder) {
                       //setSurfaceSize(getWidth(), getHeight());
                       toast1.setGravity(Gravity.CENTER_VERTICAL, 0, 0);
                       toast1.show();
                       createSprites();
                       gameLoopThread.setRunning(true);
                       gameLoopThread.start();
                       //banner();
                }

                @Override
                public void surfaceChanged(SurfaceHolder holder, int format,
                              int width, int height) {
                }
         });

   }

   private void createSprites() {
         sprites.add(createSprite(R.drawable.bubble1));
         sprites.add(createSprite(R.drawable.bubble2));
         sprites.add(createSprite(R.drawable.bubble3));
         sprites.add(createSprite(R.drawable.bubble4));
         sprites.add(createSprite(R.drawable.bubble5));
         sprites.add(createSprite(R.drawable.bubble6));
         sprites.add(createSprite(R.drawable.bubble7));
         sprites.add(createSprite(R.drawable.bubble8));
         sprites.add(createSprite(R.drawable.bubble9));
         sprites.add(createSprite(R.drawable.bubble10));
         for (int i = 0; i <= 10; i++){
            bubbleValue[i] = sprites.indexOf(i);
         }
   }

   private Sprite createSprite(int resource) {
         Bitmap bmp = BitmapFactory.decodeResource(getResources(), resource);
         return new Sprite(this, bmp);
   }


   public void setSurfaceSize(int width, int height)
   {
      synchronized (surfaceHolder)
      {
         int canvasWidth = width;
         int canvasHeight = height;

         backgroundImage = Bitmap.createScaledBitmap(backgroundImage, width, height, true);
      }
   }


   @Override
   protected void onDraw(Canvas canvas) {
         canvas.drawColor(Color.WHITE);
         //levelbanner1.draw(canvas);//causes error when applied;for reference only
         for (int i = temps.size() - 1; i >= 0; i--) {
             temps.get(i).onDraw(canvas);
         }
         for (Sprite sprite : sprites) {
             timer.draw(canvas);
             //formulaBox.draw(canvas);   
             sprite.onDraw(canvas);
         }

         if (sprites.size() == 0){
             morebanner.draw(canvas);
         }

   }

   @Override
   public boolean onTouchEvent(MotionEvent event) {
         if (System.currentTimeMillis() - lastClick > 300) {
                lastClick = System.currentTimeMillis();
                float x = event.getX();
                float y = event.getY();
                synchronized (getHolder()) {
                       for (int i = sprites.size() - 1; i >= 0; i--) {
                              Sprite sprite = sprites.get(i);
                              if (sprite.isCollition(x, y)) {
                                    sprites.remove(sprite);
                                    temps.add(new TempSprite(temps, this, x, y, pop));
                                    break;
                              }
                       }
                }
         }
         return true;
   }


   public void update(){


       //for possible check of collision bet. sprites
       //

   }

}

I've tried assigning a Rect for the sprites here and checking collision on the bottom update() function but result gets awry and produces a runtime error. Probably would be better if its automated in the Sprite class update() function, just as it does for border collision.

0
votes

If you want to have nice and proper collisions between your sprites, maybe looking at a physics engine like http://www.jbox2d.org/ would help.

It will handle a lot of the complex specific cases for you (tunnelling, time of impact, broadphase for early discard...)