有很多像我这样的类似问题,但这些问题对我没有帮助。
我正在制作游戏。游戏线程,SurfaceView和Activity已经完成并且到目前为止工作。问题是画布没有重绘。在启动时,它会在背景上绘制图标,但在每个刻度线上,图标都不会移动(它应该每秒移动一次)。我想提一下,我从来不需要打电话给 postInvalidate 。我有一个工作示例,我从来没有调用它,但它在我当前的例子中不起作用(我不想更深入,因为我实际上不需要调用它)。我从我的工作示例中复制了当前代码,概念和实现方式完全相同,但我当前的代码不刷新画布。当我在 onDraw 方法中记录绘图位置时,我看到它的坐标每秒都按预期更新,所以我可以确定这是一个画布绘图问题。我已经搜索了几个小时,但我没有找到与我的工作示例有什么不同(除了我正在使用另一个Android版本而且我没有扩展线程但是实现了Runnable,因为扩展线程是一种糟糕的风格。但是,我还扩展线程,看是否有任何差异,但它没有帮助)。我已经尝试使用 canvas.drawColor(Color.BLACK)来清理画布,但这也没有帮助。我已经尝试使用背景颜色而不是每个刻度随机变化的背景图像,但它没有改变但总是保持不变。 我发现在第一次调用时画布的密度为(例如)240。在第二次调整后,画布密度始终为0.我知道密度在这里对我没有帮助,但也许它是一个重要的信息对于某人。
以下是重要的课程......
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/gameContainer"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<com.mydomain.mygame.base.game.GameSurface
android:id="@+id/gameSurface"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1.0"
android:background="@drawable/background_game" >
</com.mydomain.mygame.base.game.GameSurface>
<!-- ...more definitions -->
</LinearLayout>
public class GameActivity extends Activity
{
@SuppressWarnings("unused")
private GameSurface gameSurface;
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.game);
gameSurface = (GameSurface)findViewById(R.id.gameSurface);
//TODO on button click -> execute methods
}
}
public class GameSurface extends SurfaceView implements SurfaceHolder.Callback
{
private GameThread thread;
protected final static int TICK_FREQUENCY = 100;// ms, stays always the same. It's a technical constant which doesn't change
private static final String TAG = GameSurface.class.getSimpleName();
public GameSurface(Context context, AttributeSet attrs)
{
super(context, attrs);
ShapeManager.INSTANCE.init(context);
SurfaceHolder holder = getHolder();
holder.addCallback(this);
setFocusable(true); // make sure we get key events
thread = new GameThread(holder, this);
}
public void updateStatus()
{
GameProcessor.INSTANCE.updateShapes();
}
@Override
protected void onDraw(Canvas canvas)
{
for (Shape shape : GameProcessor.INSTANCE.getShapes())
{
Log.i(TAG, "getX()=" + shape.getX() + ", getY()=" + shape.getY());
canvas.drawBitmap(shape.getBitmap(), shape.getX(), shape.getY(), null);
}
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height)
{
//will never invoked since we only operate in landscape
}
@Override
public void surfaceCreated(SurfaceHolder holder)
{
// start the thread here so we don't busy-wait in run
thread.setRunning(true);
new Thread(thread).start();
}
@Override
public void surfaceDestroyed(SurfaceHolder holder)
{
Log.i(TAG, "executing surfaceDestroyed()...");
thread.setRunning(false);
}
}
public class GameThread implements Runnable
{
private SurfaceHolder surfaceHolder;
private boolean running = false;
private GameSurface gameSurface;
private long lastTick;
public GameThread(SurfaceHolder surfaceHolder, GameSurface gameSurface)
{
this.surfaceHolder = surfaceHolder;
this.gameSurface = gameSurface;
lastTick = System.currentTimeMillis();
}
@Override
public void run()
{
Canvas canvas;
while (running)
{
canvas = null;
if (System.currentTimeMillis() > lastTick + GameSurface.TICK_FREQUENCY)
{
long timeDifference = System.currentTimeMillis() - (lastTick + GameSurface.TICK_FREQUENCY);
try
{
canvas = surfaceHolder.lockCanvas(null);
synchronized (surfaceHolder)
{
gameSurface.updateStatus();
gameSurface.draw(canvas);
}
}
finally
{
if (canvas != null)
{
surfaceHolder.unlockCanvasAndPost(canvas);
}
}
lastTick = System.currentTimeMillis() - timeDifference;
}
}
}
public void setRunning(boolean running)
{
this.running = running;
}
}
为什么此代码不更新我的画布的任何想法?我无法解释。我不发布 ShapeManager 和 GameProcessor ,因为它们与问题没有任何关系(它们只加载和控制游戏的当前状态和速度)。
我发现在游戏线程开始之前调用onDraw()。这意味着在线程使用它之前会将 canvas 传递给此方法。有趣的是,在线程启动后,它总是使用相同的画布,但是它不是第一次传递的画布引用。虽然每次打勾都会分配 canvas = surfaceHolder.lockCanvas(null); ,但它始终是相同的引用,但它不是原始引用。 在我的一个工作示例中,引用始终是相同的,因为我在构造函数初始化时创建位图。我不能在我当前的实现中这样做,因为我必须使用onMeasure()获得的值进行计算,该值比构造函数晚得多。
我试图以某种方式将原始画布传递给线程,但引用仍然会更改。同时我认为这是问题,但我不知道如何解决它。
答案 0 :(得分:2)
经常发生的事情,我自己找到了解决方案。 显然,它吸引到不同的画布实例是一个真正的问题。我还不确定为什么会这样。以前没有遇到过这个问题。不过,我可以通过在我的GameSurface构造函数中设置 setWillNotDraw(true); 并且我不能在我的线程中调用gameSurface.draw(canvas)来避免绘制到画布,但是gameSurface.postInvalidate()代替。强>