1

I'm trying to develop a game using a transparent canvas and a surfaceView, I use the canvas to paint and it works fine.

Now I want to add objects that will move on the screen, for example bouncing balls. I want to use a new thread for the balls, (because otherwise if it's the same thread of the surfaceView it doesn't move smoothly ).

So I'm having trouble of doing this. Can you please advise me how and when should I send the same canvas to a new ball object and then return it back to the surfaceview.
I'm not sure what the best way to handle this is, I tried using a ball as a view in the xml layout, and it worked perfect on another thread but it doesn't make sense to create 1000 views when I can just draw them on a canvas.

Any insight will be helpful!

This is my code:

    public class SurfaceMyPaint extends SurfaceView implements Runnable 
   {
        Thread t;
        SurfaceHolder holder;
        Bitmap brush;
        boolean isItOk = false;

    public SurfaceMyPaint(Context context) 
    {
        super(context);
        holder = getHolder();
        initial();
    }

    public void initial() 
    {
        brush= BitmapFactory.decodeResource(getResources(), R.drawable.brush2);       
    }

    public boolean onTouchEvent(MotionEvent event) 
    {
        if(event.getAction()== MotionEvent.ACTION_DOWN)
        {            
           x= event.getX();
           y= event.getY();
        }

       if(event.getAction()== MotionEvent.ACTION_MOVE)
       {
         x = event.getX();
         y= event.getY();
       }
       return true;
    }


    public void run()
    {
        while (isItOk == true)
        {
        if (!holder.getSurface().isValid())
            continue;
        myCanvas_w = getWidth();
        myCanvas_h = getHeight();
        if (result == null)
        result = Bitmap.createBitmap(myCanvas_w, myCanvas_h, Bitmap.Config.ARGB_8888);
        Canvas c = new Canvas(result);
        canvas = holder.lockCanvas(null);
        c.drawBitmap(brush, x - (brush.getWidth() / 2), y - (brush.getWidth() / 2), null);
         canvas.drawBitmap(result, 0, 0, null);

// How can I add this here: Ball ball = new Ball (canvas)????

        holder.unlockCanvasAndPost(canvas);
        }
    }

     public void pause(){
    isItOk = false;
    while (true){
        try {
            t.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        break;
    }
    t=null;
   }
    public void resume()
     {
        isItOk = true;
        t = new Thread(this);
        t.start();
     }

}

fadden
  • 51,356
  • 5
  • 116
  • 166
SHAI
  • 789
  • 3
  • 10
  • 43

1 Answers1

0

Summarizing your rendering code:

  1. Create a screen-sized off-screen bitmap, which you hold in a variable called "result" that isn't declared in the code you show. I assume this is a field, and the allocation only happens once?
  2. Each time, you create a new Canvas for that Bitmap.
  3. You draw on the Bitmap, with drawBitmap().
  4. You copy the Bitmap to the Surface, with drawBitmap().

You want to add a step #5, "draw Ball".

The obvious place to do the ball drawing is in step #3, but I'm going to assume you're not doing it there because that has some relatively static content that you update infrequently but want to blend in every frame.

That being the case, you should just draw the balls onto the Canvas you got back from SurfaceHolder. What you must not do is store a reference to the Surface's Canvas in the Ball object itself, which it appears you want to do (based on new Ball(canvas)). Once you call unlockCanvasAndPost() you must not use that Canvas anymore.

I don't really see an advantage to using multiple threads with your current code. If the "background" Bitmap were also changing you could render that with a different thread, and merge in the current version when you draw, but I suspect that will be more trouble than it's worth -- you will have to deal with the synchronization issues, and I don't think it'll solve your non-smoothness.

fadden
  • 51,356
  • 5
  • 116
  • 166
  • Thanks for your answer. But Let's say I want to add 1000 falling balls to my Canvas , I can't see how it can work without a different thread , since my canvas already "busy" painting my brush. And I already tried it and the ball didn't move smoothly. What other options do I have? – SHAI Sep 20 '15 at 06:57
  • 1
    I don't understand why you believe using an additional thread is going to solve your issue. I'm concerned that you have decided upon a solution without understanding the problem, specifically: why is the ball not moving smoothly? Does a single ball not move smoothly? In what way is it not smooth -- consistent but slow updates, inconsistent frame rate, changes in movement direction, flickering, ...? Have you profiled your code? Does the problem go away if you replace your brush-Bitmap-copy with a simple screen clear? – fadden Sep 20 '15 at 14:54
  • Yes, I'm talking now about a single ball. The ball's drawBitmap gets a different Y position `y=y++` every time (inside the run-while loop), this way it looks as if the ball is falling down. By "not smooth" I mean that it's not consistent, I mean it does go down , but I guess some iterations are processed faster than others, which is what makes the ball go down "fast" and then "slow" (no much difference between "fast" and "slow"). – SHAI Sep 20 '15 at 15:19
  • You may need to change your approach to rendering, or reduce your target frame rate. Rendering to a SurfaceView Surface with Canvas is done in software; rendering to a View with Canvas is hardware-accelerated; rendering to a SurfaceView Surface with OpenGL ES is all hardware. If you drag your finger around the screen while it runs, does the animation get smoother (http://stackoverflow.com/questions/26860156/)? See also https://source.android.com/devices/graphics/architecture.html#loops for some ideas on loop structure. – fadden Sep 20 '15 at 16:06
  • The problem is that if I will change something with the rendering it will also affect my paint brush drawings. This is why I wanted a different thread in the beginning. I'll try to think about it. Thanks for your help. – SHAI Sep 20 '15 at 18:26