2012-10-15 157 views
6

我正在使用线程绘制画布以创建简单的游戏引擎,但我遇到了一些我无法解释的奇怪问题。 这个“游戏”的目的是在画布上每秒画一个圆圈。 这是有效的,但不是我希望它工作的方式,似乎应用程序正在两个画布之间切换,并在每个画布上添加一个圆,以便每秒钟在两个画布之间切换,并且具有相同数量的圆,但在不同的画布中放在画布上。Android SurfaceView使用线程绘制画布

我不知道我在做什么错,但我不熟悉Treadding,有没有与我的Android设备有多少核心或类似的东西?

我的代码如下所示,所以我只使用一个launchthread,它使用一个链接到启动线程的animationthread的布局文件,并且每秒在画布上绘制一个圆。 (你可以忽略touchevent,它尚未使用)。

该项目存在了主launchthread的:

public class MainActivity extends Activity { 

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

使用这种布局文件:

<?xml version="1.0" encoding="utf-8"?> 
<FrameLayout 
    xmlns:android="http://schemas.android.com/apk/res/android" 
    android:layout_width="fill_parent" 
    android:layout_height="fill_parent">  
     <com.androidtesting.AnimationView 
      android:id="@+id/aview" 
      android:layout_width="fill_parent" 
      android:layout_height="fill_parent"/> 
</FrameLayout> 

而且我有内螺纹类Surfaceview类:

class AnimationView extends SurfaceView implements SurfaceHolder.Callback { 
    private boolean touched = false; 
    private float touched_x, touched_y = 0; 
    private Paint paint; 
    private Canvas c; 
    private Random random; 
    private AnimationThread thread; 

    public AnimationView(Context context, AttributeSet attrs) { 
     super(context, attrs); 

     SurfaceHolder holder = getHolder(); 
     holder.addCallback(this); 

     thread = new AnimationThread(holder); 
    } 

    class AnimationThread extends Thread { 
     private boolean mRun;  
     private SurfaceHolder mSurfaceHolder;   

     public AnimationThread(SurfaceHolder surfaceHolder) { 
      mSurfaceHolder = surfaceHolder; 
      paint = new Paint(); 
      paint.setARGB(255,255,255,255); 
      paint.setTextSize(32); 
     } 

     @Override 
     public void run() { 
      while (mRun) { 
       c = null; 
       try { 
        c = mSurfaceHolder.lockCanvas(null); 
        synchronized (mSurfaceHolder) {     
         doDraw(c); 
         sleep(1000); 
        } 
       } catch (Exception e) {     
        e.printStackTrace(); 
       }finally { 
        if (c != null) { 
         mSurfaceHolder.unlockCanvasAndPost(c); 
        } 
       } 
      } 
     } 

     private void doDraw(Canvas canvas) { 
      //clear the canvas 
      //canvas.drawColor(Color.BLACK);       

      random = new Random(); 
      int w = canvas.getWidth(); 
      int h = canvas.getHeight(); 
      int x = random.nextInt(w-50); 
      int y = random.nextInt(h-50); 
      int r = random.nextInt(255); 
      int g = random.nextInt(255); 
      int b = random.nextInt(255); 
      int size = 20; 
      canvas.drawCircle(x,y,size,paint);    
      canvas.restore(); 
     } 
     public void setRunning(boolean b) { 
      mRun = b; 
     } 
    } 

    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { 

    } 

    @Override 
    public boolean onTouchEvent(MotionEvent event) { 
      touched_x = event.getX(); 
      touched_y = event.getY(); 

      int action = event.getAction(); 

      switch(action){ 
       case MotionEvent.ACTION_DOWN:   
        touched = true; 
        break; 
       case MotionEvent.ACTION_MOVE: 
        touched = true; 
        break;   
       default: 
        touched = false; 
        break; 
      } 

      return true; 
    } 

    public void surfaceCreated(SurfaceHolder holder) { 
     thread.setRunning(true); 
     thread.start(); 
    } 

    public void surfaceDestroyed(SurfaceHolder holder) { 
     boolean retry = true; 
     thread.setRunning(false); 
     while (retry) { 
      try { 
       thread.join(); 
       retry = false; 
      } catch (InterruptedException e) { 
      } 
     } 
    } 
} 
+0

这应该是你的代码中的AnimationView2吗?一个更正的版本将不胜感激。 – RichieHH

+0

(ps当你从一个示例代码中复制代码时(这是一个轻微修改的LunarLander),它总是最好的说明它,因为它使得更容易找到bug))。 – RichieHH

回答

4

它似乎应用程序之间切换两个ca nvasses

是的,这是它是如何工作的。这就是所谓的双缓冲,你需要重新绘制所有的帧each time

表面的内容不会保留unlockCanvas()和lockCanvas()之间,由于这个原因,表面区域内的每一个像素必须是书面。

因此,您需要将此行canvas.drawColor(Color.BLACK)取消注释在您的代码中。

而且您不应该在画布被锁定时致电Thread.sleep(1000),否则会导致starvation问题。

+0

好的,谢谢你的回答,所以我需要某种让我们说ArrayList的地方,我保留我的所有圆对象,然后循环ArrayList绘制方法绘制圆? – randomizer

+0

如果你想每秒钟添加一个圆圈,并且想要一次绘制所有圆圈,那么是的,你需要在列表中存储关于它们的信息,每帧遍历这个列表并绘制所有的圆圈。 –

+0

好吧thx,现在所有的运行:) – randomizer

0

这听起来像你有这个工作,但我只是注意到一个小错误,我应该指出。

您在未事先调用canvas.save()的情况下调用了canvas.restore()。 来自Canvas的Android开发人员参考:“调用restore()比调用save()更多次是错误的。”

我没有看到任何理由让您在您的情况下调用canvas.save(),因此您应该删除对canvas.restore()的调用。

+0

你能帮我一下吗? http://stackoverflow.com/questions/33909257/canvas-draw-functions-not-working-after-screen-locked-and-unlocked – Jas