How can I correctly use the Timer and TimerTask Methods in Java to create a constantly oscallating moving object on a canvas?
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 surfac开发者_C百科eCreated(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 will offer a suggestion, and that is to not use a TimerTask
or Timer
to update your Canvas
.
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.
精彩评论