简体   繁体   English

如何正确使用 Java 中的 Timer 和 TimerTask 方法在 canvas 上创建一个不断摆动的移动 object?

[英]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.我正在尝试创建一个使用 canvas 绘制位图的 2D 游戏,这些位图是游戏中的对象。 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.目前,我在屏幕上来回移动 object 时遇到问题(对象的名称是目标。)我尝试使用 Timer 和 TimerTask 作为使其工作的方法,以及创建一个新的处理程序,但没有似乎工作。 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; MainActivity代码(不是很重要,只是触发有问题的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:这是我的 GameActivity 代码:

    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 will offer a suggestion, and that is to not use a TimerTask or Timer to update your Canvas .我将提供一个建议,那就是不要使用TimerTaskTimer来更新您的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.您应该有一个后台线程来更新 canvas,并且您的活动生命周期方法应该管理启动和停止线程。

This link may be helpful as an example.作为示例,此链接可能会有所帮助。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM