Android 开发中:Canvas 显示不正确
Android Developing: Canvas not displayed correctly
我是 android 开发的新手,并尝试实现一个简单的游戏,该游戏是通过表面视图和 canvas 实现的。我使用 LunarView 示例作为草稿。
想法是让一个人(通过触摸事件控制移动)和一个跟随他的僵尸。
到目前为止,我有以下 classes(我删除了我认为无用的代码):
1) 主要Activity
public class MainActivity extends ActionBarActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
}
2) ZombieView with the innner class ZombieThread and Person (Person 仅用于保存数据需要)
public class ZombieView extends SurfaceView implements SurfaceHolder.Callback {
//Thread Class that performs drawing on Canvas
class ZombieThread extends Thread {
class Person {
...
}
private final SurfaceHolder surfaceHolder;
private ZombieView zombieView;
private Context context;
private boolean running = false;
//Canvas info
private int mCanvasWidth = 1;
private int mCanvasHeight = 1;
private Bitmap mBackgroundImage;
private final Drawable mHumanImage;
private final Drawable mZombieImage;
private Resources res;
//Game Variables
double hSpeed = 1;
double zSpeed = 0.8;
Person zombie;
Person human;
public ZombieThread(SurfaceHolder holder, ZombieView zombie, Context context) {
this.surfaceHolder = holder;
this.zombieView = zombie;
this.context = context;
this.zombie = new Person(100, 100, hSpeed);
this.zombie.setRunning(true); //zombie always walks
this.human = new Person(100, 200, zSpeed);
res = context.getResources();
mHumanImage = context.getResources().getDrawable(R.drawable.green_circle);
mZombieImage = context.getResources().getDrawable(R.drawable.red_circle);
mBackgroundImage = BitmapFactory.decodeResource(res,R.drawable.background);
}
@Override
public void run() {
Canvas c = null;
while (this.running) {
try {
c = surfaceHolder.lockCanvas(null);
synchronized (surfaceHolder) {
play();
onDraw(c);
checkCollision();
}
} finally {
if (c != null) {
surfaceHolder.unlockCanvasAndPost(c);
}
}
try {
sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public void checkCollision() {
//do something
}
public void play() {
...
}
public void onDraw(Canvas c) {
//Do your drawing here...
// c.drawColor(Color.rgb(10, 0, 0));
c.drawBitmap(mBackgroundImage, 0, 0, null);
c.save();
//draw human and zombie
int width = mHumanImage.getIntrinsicWidth();
int height = mHumanImage.getIntrinsicHeight();
mHumanImage.setBounds((int) human.getX() - (width / 2), (int) human.getY() - (height / 2),
(int) human.getX() + (width / 2), (int) human.getY() + (height / 2));
mHumanImage.draw(c);
width = mZombieImage.getIntrinsicWidth();
height = mZombieImage.getIntrinsicHeight();
mZombieImage.setBounds((int) zombie.getX() - (width / 2), (int) zombie.getY() - (height / 2),
(int) zombie.getX() + (width / 2), (int) zombie.getY() + (height / 2));
mZombieImage.draw(c);
c.restore();
}
public boolean doTouchEvent(MotionEvent e) {
//do something
}
}
//ZombieView variables
private ZombieThread thread;
private final SurfaceHolder surfaceHolder;
private Context context;
public ZombieView(Context context) {
super(context);
surfaceHolder = getHolder();
surfaceHolder.addCallback(this);
this.context = context;
setFocusable(true); //makes sure we receive key-events
}
public ZombieView(Context context, AttributeSet attrs) {
super(context, attrs);
surfaceHolder = getHolder();
surfaceHolder.addCallback(this);
this.context = context;
setFocusable(true); //makes sure we receive key-events
}
public ZombieView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
surfaceHolder = getHolder();
surfaceHolder.addCallback(this);
this.context = context;
setFocusable(true); //makes sure we receive key-events
}
public ZombieThread getThread() {
return thread;
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
thread = new ZombieThread(surfaceHolder, this, context);
thread.setRunning(true);
thread.start();
}
}
XML:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
android:layout_height="match_parent" android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:paddingBottom="@dimen/activity_vertical_margin" tools:context=".MainActivity">
<com.example.zombierun.zombierun.ZombieView android:background="#ccc"
android:layout_width="match_parent" android:layout_height="match_parent" android:paddingLeft="20dp"
android:paddingBottom="40dp"
android:focusable="true"
android:visibility="visible"
android:id="@+id/customView" />
所以我现在的问题是:
当我启动应用程序时,我看到 Activity 和一个灰色区域,应该是 canvas / surfaceview。不幸的是,仅此而已。但是,当我通过按下主页按钮最小化应用程序时,我看到应用程序最小化时的 canvas(带有图像和背景颜色)。 logcat.
中没有显示错误
我假设 canvas 以某种方式停留在后台,或者不同视图之间存在重叠?这可能吗?
希望有人能帮我正确显示canvas。
提前致谢
在使用 SurfaceView 时不能使用 android:background="x"。您必须在 onDraw(Canvas c) 调用中手动绘制颜色,在本例中为 canvas.drawColor(Color.GREY) 。否则,您正在做的是让您设置的背景颜色绘制在表面视图的表面上,将其呈现为不透明的灰色。调用 onPause 时,视图被拆除,您可以暂时看到视图 window 覆盖层下方的表面,该表面绘制了 #ccc。
另外:为什么每帧让线程休眠 1/10 秒?你应该删除这一行。或者,如果您尝试以帧速率为目标:实现 1000 ms / 100 ms = 10 帧,也就是说,您正在以 10 fps 的速度绘制。
我是 android 开发的新手,并尝试实现一个简单的游戏,该游戏是通过表面视图和 canvas 实现的。我使用 LunarView 示例作为草稿。
想法是让一个人(通过触摸事件控制移动)和一个跟随他的僵尸。
到目前为止,我有以下 classes(我删除了我认为无用的代码):
1) 主要Activity
public class MainActivity extends ActionBarActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
}
2) ZombieView with the innner class ZombieThread and Person (Person 仅用于保存数据需要)
public class ZombieView extends SurfaceView implements SurfaceHolder.Callback {
//Thread Class that performs drawing on Canvas
class ZombieThread extends Thread {
class Person {
...
}
private final SurfaceHolder surfaceHolder;
private ZombieView zombieView;
private Context context;
private boolean running = false;
//Canvas info
private int mCanvasWidth = 1;
private int mCanvasHeight = 1;
private Bitmap mBackgroundImage;
private final Drawable mHumanImage;
private final Drawable mZombieImage;
private Resources res;
//Game Variables
double hSpeed = 1;
double zSpeed = 0.8;
Person zombie;
Person human;
public ZombieThread(SurfaceHolder holder, ZombieView zombie, Context context) {
this.surfaceHolder = holder;
this.zombieView = zombie;
this.context = context;
this.zombie = new Person(100, 100, hSpeed);
this.zombie.setRunning(true); //zombie always walks
this.human = new Person(100, 200, zSpeed);
res = context.getResources();
mHumanImage = context.getResources().getDrawable(R.drawable.green_circle);
mZombieImage = context.getResources().getDrawable(R.drawable.red_circle);
mBackgroundImage = BitmapFactory.decodeResource(res,R.drawable.background);
}
@Override
public void run() {
Canvas c = null;
while (this.running) {
try {
c = surfaceHolder.lockCanvas(null);
synchronized (surfaceHolder) {
play();
onDraw(c);
checkCollision();
}
} finally {
if (c != null) {
surfaceHolder.unlockCanvasAndPost(c);
}
}
try {
sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public void checkCollision() {
//do something
}
public void play() {
...
}
public void onDraw(Canvas c) {
//Do your drawing here...
// c.drawColor(Color.rgb(10, 0, 0));
c.drawBitmap(mBackgroundImage, 0, 0, null);
c.save();
//draw human and zombie
int width = mHumanImage.getIntrinsicWidth();
int height = mHumanImage.getIntrinsicHeight();
mHumanImage.setBounds((int) human.getX() - (width / 2), (int) human.getY() - (height / 2),
(int) human.getX() + (width / 2), (int) human.getY() + (height / 2));
mHumanImage.draw(c);
width = mZombieImage.getIntrinsicWidth();
height = mZombieImage.getIntrinsicHeight();
mZombieImage.setBounds((int) zombie.getX() - (width / 2), (int) zombie.getY() - (height / 2),
(int) zombie.getX() + (width / 2), (int) zombie.getY() + (height / 2));
mZombieImage.draw(c);
c.restore();
}
public boolean doTouchEvent(MotionEvent e) {
//do something
}
}
//ZombieView variables
private ZombieThread thread;
private final SurfaceHolder surfaceHolder;
private Context context;
public ZombieView(Context context) {
super(context);
surfaceHolder = getHolder();
surfaceHolder.addCallback(this);
this.context = context;
setFocusable(true); //makes sure we receive key-events
}
public ZombieView(Context context, AttributeSet attrs) {
super(context, attrs);
surfaceHolder = getHolder();
surfaceHolder.addCallback(this);
this.context = context;
setFocusable(true); //makes sure we receive key-events
}
public ZombieView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
surfaceHolder = getHolder();
surfaceHolder.addCallback(this);
this.context = context;
setFocusable(true); //makes sure we receive key-events
}
public ZombieThread getThread() {
return thread;
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
thread = new ZombieThread(surfaceHolder, this, context);
thread.setRunning(true);
thread.start();
}
}
XML:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
android:layout_height="match_parent" android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:paddingBottom="@dimen/activity_vertical_margin" tools:context=".MainActivity">
<com.example.zombierun.zombierun.ZombieView android:background="#ccc"
android:layout_width="match_parent" android:layout_height="match_parent" android:paddingLeft="20dp"
android:paddingBottom="40dp"
android:focusable="true"
android:visibility="visible"
android:id="@+id/customView" />
所以我现在的问题是: 当我启动应用程序时,我看到 Activity 和一个灰色区域,应该是 canvas / surfaceview。不幸的是,仅此而已。但是,当我通过按下主页按钮最小化应用程序时,我看到应用程序最小化时的 canvas(带有图像和背景颜色)。 logcat.
中没有显示错误我假设 canvas 以某种方式停留在后台,或者不同视图之间存在重叠?这可能吗?
希望有人能帮我正确显示canvas。
提前致谢
在使用 SurfaceView 时不能使用 android:background="x"。您必须在 onDraw(Canvas c) 调用中手动绘制颜色,在本例中为 canvas.drawColor(Color.GREY) 。否则,您正在做的是让您设置的背景颜色绘制在表面视图的表面上,将其呈现为不透明的灰色。调用 onPause 时,视图被拆除,您可以暂时看到视图 window 覆盖层下方的表面,该表面绘制了 #ccc。
另外:为什么每帧让线程休眠 1/10 秒?你应该删除这一行。或者,如果您尝试以帧速率为目标:实现 1000 ms / 100 ms = 10 帧,也就是说,您正在以 10 fps 的速度绘制。