如何正确使用 Java 中的 Timer 和 TimerTask 方法在画布上创建不断振荡的移动对象?
我正在尝试创建一个使用画布绘制位图的 2D 游戏,这些位图是游戏中的对象。目前,我在屏幕上来回移动对象时遇到问题(对象的名称是 target。)我尝试使用 Timer 和 TimerTask 作为使其工作的方法,以及创建一个新的处理程序,但没有任何结果似乎有效。当游戏运行时,您可以看到目标在指定像素上移动一次(这是使其移动的重复计时。)然后应用程序崩溃,给出(抱歉!-强制关闭对话框。我做错了什么?
MainActivity 代码(不是很重要,只是触发有问题的 GameActivity): 包app.AngryCannonShooterActivity;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.view.Window;
import android.view.View.*;
import android.widget.Button;
public class MainActivity extends Activity {
private OnClickListener OptionsButtonListener = new OnClickListener() {
public void onClick(View v) {
Intent intent = new Intent(MainActivity.this, OptionsActivity.class);
MainActivity.this.startActivity(intent);
}
};
private OnClickListener HelpButtonListener = new OnClickListener() {
public void onClick(View v) {
Intent intent2 = new Intent(MainActivity.this, HelpActivity.class);
MainActivity.this.startActivity(intent2);
}
};
private OnClickListener LeaveButtonListener = new OnClickListener() {
public void onClick(View v) {
finish();
}
};
private OnClickListener PlayButtonListener = new OnClickListener() {
public void onClick(View v) {
Intent intent3 = new Intent(MainActivity.this, GameActivity.class);
MainActivity.this.startActivity(intent3);
}
};
private OnClickListener TestButtonListener = new OnClickListener() {
public void onClick(View v) {
Intent intent3 = new Intent(MainActivity.this, TestActivity.class);
MainActivity.this.startActivity(intent3);
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.main);
Button OptionsButton = (Button)findViewById(R.id.MainScreenOptionsButton);
OptionsButton.setOnClickListener(OptionsButtonListener);
Button LeaveButton = (Button)findViewById(R.id.MainScreenLeaveButton);
LeaveButton.setOnClickListener(LeaveButtonListener);
Button HelpButton = (Button)findViewById(R.id.MainScreenInstructionsButton);
HelpButton.setOnClickListener(HelpButtonListener);
Button PlayButton = (Button)findViewById(R.id.MainScreenPlayButton);
PlayButton.setOnClickListener(PlayButtonListener);
Button TestButton = (Button)findViewById(R.id.TestButtonMainScreen);
TestButton.setOnClickListener(TestButtonListener);
}
}
这是我的游戏活动代码:
package app.AngryCannonShooterActivity;
import java.util.ArrayList;
import java.util.Timer;
import java.util.TimerTask;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.view.View;
import android.view.Window;
import android.view.View.*;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.view.MotionEvent;
import android.view.SurfaceView;
import android.view.SurfaceHolder;
import android.view.SurfaceHolder.Callback;
import android.widget.Button;
import android.widget.LinearLayout;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.ColorFilter;
import android.graphics.Paint;
import android.graphics.Typeface;
import android.content.res.Resources;
public class GameActivity extends Activity {
//^GameActivity START^
final Handler timerhandler = new Handler();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
LinearLayout touchspread;
touchspread = new LinearLayout(this);
setContentView(new Panel(this));
touchspread.requestLayout();
}
class Panel extends SurfaceView implements SurfaceHolder.Callback {
//^Panel Class START^
private Bitmap cannon;
private Bitmap launchbutton;
private Bitmap leftbutton;
private Bitmap rightbutton;
private Bitmap target;
private ViewThread mThread;
private int mX;
private int launchbuttonxvalue;
private int launchbuttonyvalue;
private int leftbuttonxvalue;
private int leftbuttonyvalue;
private int rightbuttonxvalue;
private int rightbuttonyvalue;
private int scoretextviewxvalue;
private int scoretextviewyvalue;
private int cannonincrementmovement;
private int score;
private int cannonrestrictionpoint;
private int cannonresetpoint;
private int targetxvalue;
private int targetyvalue;
private int targetmovementincrementvalue;
public Panel (Context context) {
super(context);
cannon = BitmapFactory.decodeResource(getResources(), R.drawable.testcannon);
launchbutton = BitmapFactory.decodeResource(getResources(), R.drawable.launchbutton);
leftbutton = BitmapFactory.decodeResource(getResources(), R.drawable.leftbutton);
rightbutton = BitmapFactory.decodeResource(getResources(), R.drawable.rightbutton);
target = BitmapFactory.decodeResource(getResources(), R.drawable.testtarget);
getHolder().addCallback(this);
mThread = new ViewThread(this);
}
public Canvas canvas;
@Override
public void onDraw(Canvas canvas) {
Paint paint = new Paint();
canvas.drawColor(Color.BLACK);
paint.setColor(Color.YELLOW);
paint.setTypeface(Typeface.DEFAULT_BOLD);
paint.setAlpha(30+20*1);
canvas.drawPaint(paint);
paint.setTextSize(20);
canvas.drawText("Score: "+score, scoretextviewxvalue, scoretextviewyvalue, paint);
canvas.drawBitmap(launchbutton, launchbuttonxvalue, launchbuttonyvalue, null);
canvas.drawBitmap(cannon, mX, (float) (canvas.getHeight()-(launchbutton.getHeight()*4.2)), null);
canvas.drawBitmap(leftbutton, leftbuttonxvalue, leftbuttonyvalue, null);
canvas.drawBitmap(rightbutton, rightbuttonxvalue, rightbuttonyvalue,null);
canvas.drawBitmap(target, targetxvalue, targetyvalue, null);
launchbuttonxvalue = (int) ((canvas.getWidth()-launchbutton.getWidth())/2);
launchbuttonyvalue = (int) (canvas.getHeight()*0.92);
leftbuttonxvalue = (int) (0);
leftbuttonyvalue = (int) (canvas.getHeight()*0.9);
rightbuttonxvalue = (int) (canvas.getWidth()*0.91);
rightbuttonyvalue = (int) (canvas.getHeight()*0.9);
scoretextviewxvalue = (int) ((canvas.getWidth())/1.4);
scoretextviewyvalue = (int) ((canvas.getHeight())/15);
cannonincrementmovement = (int) (10);
score = (int) (0);
cannonrestrictionpoint = (int) ((canvas.getWidth())-cannon.getWidth());
cannonresetpoint = (int) ((canvas.getWidth()*0.9));
targetxvalue = (int) (0);
targetyvalue = (int) ((canvas.getHeight())/2.2);
targetmovementincrementvalue = (int) (5);
final Runnable timerrunnable = new Runnable() {
public void run() {
movetarget();
}
};
Timer timer = new Timer();
TimerTask task = new TimerTask() {
@Override
public void run() {
timerhandler.post(timerrunnable);
}};
timer.scheduleAtFixedRate(task, 200, 1000);
}
public int getOpacity() {
return 0;
}
public void setAlpha(int alpha) {
}
public void setColorFilter(ColorFilter cf) {
}
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
}
public void surfaceCreated(SurfaceHolder holder) {
if (!mThread.isAlive()) {
mThread = new ViewThread(this);
mThread.setRunning(true);
mThread.start();
}
}
public void surfaceDestroyed(SurfaceHolder holder) {
if (mThread.isAlive()) {
mThread.setRunning(false);
}
}
public void checkgridleftbutton() {
if (mX < 0) {
mX = (int) (0);
}
}
public void checkgridrightbutton() {
if (mX > cannonrestrictionpoint) {
mX = (int) (cannonresetpoint);
}
}
public void checktargetlocation() {
if (targetxvalue <= -1) {
invertdirection();
}
if (targetxvalue >= (canvas.getWidth()-target.getWidth())); {
invertdirection();
}
}
public void invertdirection() {
targetmovementincrementvalue = targetmovementincrementvalue*-1;
}
public void movetarget() {
targetxvalue = (int) (targetxvalue + targetmovementincrementvalue);
checktargetlocation();
}
public class ViewThread extends Thread {
//^ViewThread Class START^
private Panel mPanel;
private SurfaceHolder mHolder;
private boolean mRun = false;
public ViewThread(Panel panel) {
mPanel = panel;
mHolder = mPanel.getHolder();
}
public void setRunning(boolean run) {
mRun = run;
}
@Override
public void run() {
Canvas canvas = null;
while (mRun) {
canvas = mHolder.lockCanvas();
if (canvas != null) {
mPanel.onDraw(canvas);
mHolder.unlockCanvasAndPost(canvas);
}
}
}
}
//^ViewThread Class END^
@Override
public boolean onTouchEvent(MotionEvent event){
int action = event.getAction();
int x = (int) event.getX();
int y = (int) event.getY();
switch(action){
case MotionEvent.ACTION_DOWN:
if (x >= launchbuttonxvalue && x < (launchbuttonxvalue + launchbutton.getWidth())
&& y >= launchbuttonyvalue && y < (launchbuttonyvalue + launchbutton.getHeight())) {
finish();
}
if (x >= leftbuttonxvalue && x < (leftbuttonxvalue + leftbutton.getWidth())
&& y >= leftbuttonyvalue && y < (leftbuttonyvalue + leftbutton.getHeight())) {
mX = mX - cannonincrementmovement;
checkgridleftbutton();
}
if (x >= rightbuttonxvalue && x < (rightbuttonxvalue + rightbutton.getWidth())
&& y >= rightbuttonyvalue && y < (rightbuttonyvalue + rightbutton.getHeight())) {
mX = mX + cannonincrementmovement;
checkgridrightbutton();
}
break;
}
return super.onTouchEvent(event);
}
//^Panel Class END^
}
}
//^GameActivity Class END^
I am trying to create a 2D game that uses a canvas to draw bitmaps, with those bitmaps being objects in the game. Currently, I am having problems with moving an object back and forth across the screen (object's name is target.) I've tried using the Timer and TimerTask as means of getting this to work, as well as creating a new Handler, but nothing seems to work. When the game runs, you can see the target move once over the specified pixels (it's a repetitive timing that makes it move.) Then the app crashes giving me the (Sorry!-Force Close Dialog. What am I doing wrong?
MainActivity Code(not really important, just triggers the problematic GameActivity):
package app.AngryCannonShooterActivity;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.view.Window;
import android.view.View.*;
import android.widget.Button;
public class MainActivity extends Activity {
private OnClickListener OptionsButtonListener = new OnClickListener() {
public void onClick(View v) {
Intent intent = new Intent(MainActivity.this, OptionsActivity.class);
MainActivity.this.startActivity(intent);
}
};
private OnClickListener HelpButtonListener = new OnClickListener() {
public void onClick(View v) {
Intent intent2 = new Intent(MainActivity.this, HelpActivity.class);
MainActivity.this.startActivity(intent2);
}
};
private OnClickListener LeaveButtonListener = new OnClickListener() {
public void onClick(View v) {
finish();
}
};
private OnClickListener PlayButtonListener = new OnClickListener() {
public void onClick(View v) {
Intent intent3 = new Intent(MainActivity.this, GameActivity.class);
MainActivity.this.startActivity(intent3);
}
};
private OnClickListener TestButtonListener = new OnClickListener() {
public void onClick(View v) {
Intent intent3 = new Intent(MainActivity.this, TestActivity.class);
MainActivity.this.startActivity(intent3);
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.main);
Button OptionsButton = (Button)findViewById(R.id.MainScreenOptionsButton);
OptionsButton.setOnClickListener(OptionsButtonListener);
Button LeaveButton = (Button)findViewById(R.id.MainScreenLeaveButton);
LeaveButton.setOnClickListener(LeaveButtonListener);
Button HelpButton = (Button)findViewById(R.id.MainScreenInstructionsButton);
HelpButton.setOnClickListener(HelpButtonListener);
Button PlayButton = (Button)findViewById(R.id.MainScreenPlayButton);
PlayButton.setOnClickListener(PlayButtonListener);
Button TestButton = (Button)findViewById(R.id.TestButtonMainScreen);
TestButton.setOnClickListener(TestButtonListener);
}
}
And here's my GameActivity Code:
package app.AngryCannonShooterActivity;
import java.util.ArrayList;
import java.util.Timer;
import java.util.TimerTask;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.view.View;
import android.view.Window;
import android.view.View.*;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.view.MotionEvent;
import android.view.SurfaceView;
import android.view.SurfaceHolder;
import android.view.SurfaceHolder.Callback;
import android.widget.Button;
import android.widget.LinearLayout;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.ColorFilter;
import android.graphics.Paint;
import android.graphics.Typeface;
import android.content.res.Resources;
public class GameActivity extends Activity {
//^GameActivity START^
final Handler timerhandler = new Handler();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
LinearLayout touchspread;
touchspread = new LinearLayout(this);
setContentView(new Panel(this));
touchspread.requestLayout();
}
class Panel extends SurfaceView implements SurfaceHolder.Callback {
//^Panel Class START^
private Bitmap cannon;
private Bitmap launchbutton;
private Bitmap leftbutton;
private Bitmap rightbutton;
private Bitmap target;
private ViewThread mThread;
private int mX;
private int launchbuttonxvalue;
private int launchbuttonyvalue;
private int leftbuttonxvalue;
private int leftbuttonyvalue;
private int rightbuttonxvalue;
private int rightbuttonyvalue;
private int scoretextviewxvalue;
private int scoretextviewyvalue;
private int cannonincrementmovement;
private int score;
private int cannonrestrictionpoint;
private int cannonresetpoint;
private int targetxvalue;
private int targetyvalue;
private int targetmovementincrementvalue;
public Panel (Context context) {
super(context);
cannon = BitmapFactory.decodeResource(getResources(), R.drawable.testcannon);
launchbutton = BitmapFactory.decodeResource(getResources(), R.drawable.launchbutton);
leftbutton = BitmapFactory.decodeResource(getResources(), R.drawable.leftbutton);
rightbutton = BitmapFactory.decodeResource(getResources(), R.drawable.rightbutton);
target = BitmapFactory.decodeResource(getResources(), R.drawable.testtarget);
getHolder().addCallback(this);
mThread = new ViewThread(this);
}
public Canvas canvas;
@Override
public void onDraw(Canvas canvas) {
Paint paint = new Paint();
canvas.drawColor(Color.BLACK);
paint.setColor(Color.YELLOW);
paint.setTypeface(Typeface.DEFAULT_BOLD);
paint.setAlpha(30+20*1);
canvas.drawPaint(paint);
paint.setTextSize(20);
canvas.drawText("Score: "+score, scoretextviewxvalue, scoretextviewyvalue, paint);
canvas.drawBitmap(launchbutton, launchbuttonxvalue, launchbuttonyvalue, null);
canvas.drawBitmap(cannon, mX, (float) (canvas.getHeight()-(launchbutton.getHeight()*4.2)), null);
canvas.drawBitmap(leftbutton, leftbuttonxvalue, leftbuttonyvalue, null);
canvas.drawBitmap(rightbutton, rightbuttonxvalue, rightbuttonyvalue,null);
canvas.drawBitmap(target, targetxvalue, targetyvalue, null);
launchbuttonxvalue = (int) ((canvas.getWidth()-launchbutton.getWidth())/2);
launchbuttonyvalue = (int) (canvas.getHeight()*0.92);
leftbuttonxvalue = (int) (0);
leftbuttonyvalue = (int) (canvas.getHeight()*0.9);
rightbuttonxvalue = (int) (canvas.getWidth()*0.91);
rightbuttonyvalue = (int) (canvas.getHeight()*0.9);
scoretextviewxvalue = (int) ((canvas.getWidth())/1.4);
scoretextviewyvalue = (int) ((canvas.getHeight())/15);
cannonincrementmovement = (int) (10);
score = (int) (0);
cannonrestrictionpoint = (int) ((canvas.getWidth())-cannon.getWidth());
cannonresetpoint = (int) ((canvas.getWidth()*0.9));
targetxvalue = (int) (0);
targetyvalue = (int) ((canvas.getHeight())/2.2);
targetmovementincrementvalue = (int) (5);
final Runnable timerrunnable = new Runnable() {
public void run() {
movetarget();
}
};
Timer timer = new Timer();
TimerTask task = new TimerTask() {
@Override
public void run() {
timerhandler.post(timerrunnable);
}};
timer.scheduleAtFixedRate(task, 200, 1000);
}
public int getOpacity() {
return 0;
}
public void setAlpha(int alpha) {
}
public void setColorFilter(ColorFilter cf) {
}
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
}
public void surfaceCreated(SurfaceHolder holder) {
if (!mThread.isAlive()) {
mThread = new ViewThread(this);
mThread.setRunning(true);
mThread.start();
}
}
public void surfaceDestroyed(SurfaceHolder holder) {
if (mThread.isAlive()) {
mThread.setRunning(false);
}
}
public void checkgridleftbutton() {
if (mX < 0) {
mX = (int) (0);
}
}
public void checkgridrightbutton() {
if (mX > cannonrestrictionpoint) {
mX = (int) (cannonresetpoint);
}
}
public void checktargetlocation() {
if (targetxvalue <= -1) {
invertdirection();
}
if (targetxvalue >= (canvas.getWidth()-target.getWidth())); {
invertdirection();
}
}
public void invertdirection() {
targetmovementincrementvalue = targetmovementincrementvalue*-1;
}
public void movetarget() {
targetxvalue = (int) (targetxvalue + targetmovementincrementvalue);
checktargetlocation();
}
public class ViewThread extends Thread {
//^ViewThread Class START^
private Panel mPanel;
private SurfaceHolder mHolder;
private boolean mRun = false;
public ViewThread(Panel panel) {
mPanel = panel;
mHolder = mPanel.getHolder();
}
public void setRunning(boolean run) {
mRun = run;
}
@Override
public void run() {
Canvas canvas = null;
while (mRun) {
canvas = mHolder.lockCanvas();
if (canvas != null) {
mPanel.onDraw(canvas);
mHolder.unlockCanvasAndPost(canvas);
}
}
}
}
//^ViewThread Class END^
@Override
public boolean onTouchEvent(MotionEvent event){
int action = event.getAction();
int x = (int) event.getX();
int y = (int) event.getY();
switch(action){
case MotionEvent.ACTION_DOWN:
if (x >= launchbuttonxvalue && x < (launchbuttonxvalue + launchbutton.getWidth())
&& y >= launchbuttonyvalue && y < (launchbuttonyvalue + launchbutton.getHeight())) {
finish();
}
if (x >= leftbuttonxvalue && x < (leftbuttonxvalue + leftbutton.getWidth())
&& y >= leftbuttonyvalue && y < (leftbuttonyvalue + leftbutton.getHeight())) {
mX = mX - cannonincrementmovement;
checkgridleftbutton();
}
if (x >= rightbuttonxvalue && x < (rightbuttonxvalue + rightbutton.getWidth())
&& y >= rightbuttonyvalue && y < (rightbuttonyvalue + rightbutton.getHeight())) {
mX = mX + cannonincrementmovement;
checkgridrightbutton();
}
break;
}
return super.onTouchEvent(event);
}
//^Panel Class END^
}
}
//^GameActivity Class END^
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
我会提供一个建议,那就是不要使用
TimerTask
或Timer
来更新您的Canvas
。您应该有一个后台线程来更新画布,并且您的活动生命周期方法应该管理启动和停止线程。
此链接作为示例可能会有所帮助。
I will offer a suggestion, and that is to not use a
TimerTask
orTimer
to update yourCanvas
.You should have a background thread which will do the updating to the canvas, and your Activities lifecycle methods should manage starting and stopping the thread.
This link may be helpful as an example.