Android uses Canvas and painting for Learning and Its Application for gesture sensing (Table Tennis Games) and androidcanvas

Source: Internet
Author: User

Android uses Canvas and painting for Learning and Its Application for gesture sensing (Table Tennis Games) and androidcanvas

As a rookie who has not studied Android, he has recently worked hard to learn how to use Android. This week, I read the Android plotting, mainly Canvas and painting. I feel that I need to practice it. In the afternoon, I just want to play a whole table tennis game, which is to consolidate my learning knowledge.

First, you need to understand the common classes to be mastered for Android plotting, including Canvas. Just like a Canvas, everything is painted on it. painting is a Paint brush, you can use it to draw a variety of basic graphics and text. The commonly used methods of Canvas and painting are not listed. Such things are everywhere on the Internet. With these two things, we want to implement the game, but also a gesture sensing. For this game, we only need to identify the Left shift and right shift.

Therefore, we need to use the OnGestureListener interface of Android and the GestureDetector class.

The important method is as follows:

GestureDetector detector; @ Override protected void onCreate (Bundle savedInstanceState) {super. onCreate (savedInstanceState); setContentView (R. layout. activity_start); detector = new GestureDetector (this, this);} @ Override public boolean onTouchEvent (MotionEvent event) {// TODO Auto-generated method stub return detector. onTouchEvent (event) ;}@ Override public boolean onFling (MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {// minimum movement standard float minMove = 30; if (e1.getX ()-e2.getX ()> minMove & Math. abs (velocityX)> Math. abs (velocityY) {Toast. makeText (this, "Move to Left", Toast. LENGTH_LONG ). show ();} else if (e2.getX ()-e1.getX ()> minMove & Math. abs (velocityX)> Math. abs (velocityY) {Toast. makeText (this, "Move to Right", Toast. LENGTH_LONG ). show ();} return false ;}
We need to use the onTouchEvent () method that calls GestureDetector in onTouchEvent. Only in this way can the gesture-Induced Interface be called back. In the onFling () method, we can determine the Left shift and right shift.

The game is as follows:


To achieve this game, consider the following:

1. How to describe the status of the game, specifically the status of the ball and the racket

2. How to dynamically refresh a view

For question 1, the status of the racket is relatively simple. There are only two options: Left shift and right shift. You can set the x and y coordinates of the racket. The step size can be changed very well. If you are a small ball, it is a little troublesome, we need to use its x, y coordinates, x movement speed, and y movement speed to control its status. when it encounters a strong left or right side, the x speed is reversed, and when it hits a racket or the y speed on it is reversed, when you hit the lower side (not hitting the racket), the competition is over.

For question 2, we need to start a scheduled refresh task, regularly execute the task to determine the current status, and then refresh the view based on the data.

The following describes how to implement your own games. The surrogate mother includes the following classes: TablePlayActivity, TableView, MsgDefine, TablePlayModel, and TablePlayController.

TablePlayActivity is as follows:

Package com. example. tableplay; import android. support. v7.app. actionBarActivity; import android. app. service; import android. OS. bundle; import android. OS. handler; import android. OS. message; import android. OS. vibrator; import android. util. displayMetrics; import android. util. log; import android. view. gestureDetector; import android. view. gestureDetector. onGestureListener; import android. view. menu; import android. view. menuItem; import android. view. motionEvent; import android. view. window; import android. view. windowManager; import android. widget. toast; public class TablePlayActivity extends ActionBarActivity implements extends {private includector; private TableView myView; private Vibrator vibrator; @ Override protected void onCreate (Bundle savedInstanceState) {requestWindowFeature (Window. FEATURE_NO_TITLE); super. onCreate (savedInstanceState); init (); dector = new GestureDetector (this, this); vibrator = (Vibrator) getSystemService (Service. VIBRATOR_SERVICE);} private void init () {myView = new TableView (this); setContentView (myView); getWindow (). setFlags (WindowManager. layoutParams. FLAG_FULLSCREEN, WindowManager. layoutParams. FLAG_FULLSCREEN); WindowManager wm = getWindowManager (); DisplayMetrics metrics = new DisplayMetrics (); wm. getdefadisplay display (). getMetrics (metrics); Log. I ("dingbin", "width" + metrics. widthPixels + "height" + metrics. heightPixels); TablePlayModel. getInstance (). mScreenX = metrics. widthPixels; TablePlayModel. getInstance (). mScreenY = metrics. heightPixels; TablePlayModel. getInstance (). mRacketY = metrics. heightPixels-TablePlayModel. getInstance (). SHIFT_DISTANCE; createHandler (); TablePlayController. getInstance (). startGame (mHandler);} private Handler mHandler; public void createHandler () {mHandler = new Handler () {@ Override public void handleMessage (Message msg) {super. handleMessage (msg); switch (msg. what) {case MsgDefine. MSG_TYPE_REFRESH: {myView. invalidate (); break;} case MsgDefine. MSG_TYPE_VIBROTOR: {vibrator. vibrate (1, 1000); Toast. makeText (TablePlayActivity. this, "Nice", Toast. LENGTH_SHORT ). show (); break;} default: break ;}};}@ Override public boolean onCreateOptionsMenu (Menu menu) {// Inflate the menu; this adds items to the action bar if it is present. getMenuInflater (). inflate (R. menu. table_play, menu); return true ;}@ Override public boolean onOptionsItemSelected (MenuItem item) {// Handle action bar item clicks here. the action bar will // automatically handle clicks on the Home/Up button, so long // as you specify a parent activity in AndroidManifest. xml. int id = item. getItemId (); if (id = R. id. action_settings) {return true;} return super. onOptionsItemSelected (item) ;}@ Override public boolean onTouchEvent (MotionEvent event) {return dector. onTouchEvent (event) ;}@ Override public boolean onDown (MotionEvent e) {// TODO Auto-generated method stub return false;} @ Override public void onShowPress (MotionEvent e) {// TODO Auto-generated method stub} @ Override public boolean onSingleTapUp (MotionEvent e) {// TODO Auto-generated method stub return false ;} @ Override public boolean onScroll (MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {// TODO Auto-generated method stub return false;} @ Override public void onLongPress (MotionEvent e) {// TODO Auto-generated method stub} @ Override public boolean onFling (MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {// minimum moving standard float minMove = 30; if (e1.getX ()-e2.getX ()> minMove & Math. abs (velocityX)> Math. abs (velocityY) {// left shift TablePlayController. getInstance (). racketMoveLeft ();} else if (e2.getX ()-e1.getX ()> minMove & Math. abs (velocityX)> Math. abs (velocityY) {// right shift TablePlayController. getInstance (). racketMoveRight ();} // re-paint View myView. invalidate (); return false ;}}
In the TablePlayActivity class, we mainly implement gesture sensing judgment and Handler message processing. In addition, the screen width and height are obtained during initialization.
TableView is our main drawing class. In its onDraw method, we re-paint the ball and racket. The Code is as follows:

Package com. example. tableplay; import android. content. context; import android. graphics. canvas; import android. graphics. color; import android. graphics. paint; import android. graphics. paint. style; import android. util. log; import android. view. view; import android. widget. toast; public class TableView extends View {private Paint paint; private Context mContext; public TableView (Context context) {super (context ); MContext = context; // create paint Paint = new paint (); paint. setAntiAlias (true); paint. setStyle (Style. FILL) ;}@ Override protected void onDraw (Canvas canvas) {super. onDraw (canvas); TablePlayModel data = TablePlayModel. getInstance (); if (data. isGameOver) {paint. setTextSize (80); paint. setColor (Color. BLUE); setBackgroundResource (R. drawable. game_over); canvas. drawText ("Game is over! ", 270, data. mScreenY/2, paint);} else {// paint the racket. setColor (Color. GREEN); canvas. drawRect (data. mRacketX, data. mRacketY, data. mRacketX + data. RACKET_WIDTH, data. mRacketY + data. RACKET_HEIGHT, paint); // paint the ball. setColor (Color. GRAY); canvas. drawCircle (data. mBallX, data. mBallY, data. mBallRadius, paint );}}}
The following is the data TablePlayModel, which mainly caches the data we need, including all the game statuses and constants we need to use. The Code is as follows:

Package com. example. tableplay; import java. util. random; import android. util. log; public class TablePlayModel {private static TablePlayModel mInstance = null; // width and height of the screen public int mScreenX; public int mScreenY; // width and height of the racket public final int RACKET_WIDTH = 180; public final int RACKET_HEIGHT = 25; // The Stride of the racket movement public int mRacketStep = 150; // public int mRacketX = 100; public int mRacketY; private Random rand = new Random (); // the radius of the ball is public int mBallRadius = 35; // The x and y coordinates of the ball are public int mBallX = rand. nextInt (200) + 20; public int mBallY = rand. nextInt (500) + 20; // ball x, y moving speed public int mBallYSpeed = 28; private double mXRate = rand. nextDouble ()-0.5; public int mBallXSpeed = (int) (mBallYSpeed * mXRate * 2); // Refresh Interval MS public int mTimeInterval = 100; // refresh delay MS public int mTimeDelay = 0; public final int SHIFT_DISTANCE = 200; public boolean isGameOver = false; public static TablePlayModel getInstance () {if (mInstance = null) {synchronized (TablePlayModel. class) {if (mInstance = null) {Log. I ("dingbin", "TablePlayModel. getInstance () "); mInstance = new TablePlayModel () ;}} return mInstance ;}}
Next is the most important control class TablePlayController. Our core logic is in this class. Specifically, it is to start the timer to execute the task and execute the position of the Ball Based on the current status, update the coordinates of the ball and notify the view to refresh the page. The Code is as follows:

Package com. example. tableplay; import java. util. timer; import java. util. timerTask; import android. OS. handler; import android. OS. message; import android. util. log; import android. widget. toast; public class TablePlayController {private static TablePlayController mInstance = null; private TablePlayModel data = TablePlayModel. getInstance (); private TablePlayController () {} public static TablePlayController getInstance () {if (mInstance = null) {synchronized (TablePlayController. class) {if (mInstance = null) {return new TablePlayController () ;}}return mInstance;} public void startGame (final Handler handler) {Log. I ("dingbin", "startGame"); data = TablePlayModel. getInstance (); Log. I ("dingbin", data. toString (); final Timer timer = new Timer (); timer. schedule (new TimerTask () {@ Override public void run () {// if the left and right boundary is met if (data. mBallX <= data. mBallRadius | data. mBallX> = data. mScreenX-data. mBallRadius) {data. mBallXSpeed =-data. mBallXSpeed;} // if the position is lower than the height of the racket but not within the racket range, the competition ends if (data. mBallY> data. mRacketY & (data. mBallX <data. mRacketX | data. mBallX> data. mRacketX + data. RACKET_WIDTH) {timer. cancel (); data. isGameOver = true;} else if (data. mBallY <= data. mBallRadius) {data. mBallYSpeed =-data. mBallYSpeed;} else if (data. mBallX> = data. mRacketX & data. mBallX <= data. mRacketX + data. RACKET_WIDTH & (data. mBallY + data. mBallRadius)> = data. mRacketY) {data. mBallYSpeed =-data. mBallYSpeed; Message msg = Message. obtain (handler); msg. what = MsgDefine. MSG_TYPE_VIBROTOR; msg. sendToTarget ();} // the coordinate of the ball changes data. mBallX + = data. mBallXSpeed; data. mBallY + = data. mBallYSpeed; // send the Message msg = Message. obtain (handler); msg. what = MsgDefine. MSG_TYPE_REFRESH; msg. sendToTarget () ;}}, data. mTimeDelay, data. mTimeInterval);}/** move the racket left */public void racketMoveLeft () {if (data. mRacketX> = data. mRacketStep) {data. mRacketX + =-data. mRacketStep;} else {data. mRacketX = 0 ;}}/** right shift of racket */public void racketMoveRight () {if (data. mRacketX + data. RACKET_WIDTH) <data. mScreenX) {data. mRacketX + = data. mRacketStep;} else {data. mRacketX = data. mScreenX-data. RACKET_WIDTH ;}}}
In order to achieve better results, we will shake the ball when it is hit successfully (it needs to be done in AndroidManifest. add <uses-permission android: name = "android. permission. VIBRATE "/>) and play toast to congratulate you.

Finally, the information data class MsgDefine stores the data type. Specifically, it includes refreshing messages and vibrating messages. The Code is as follows:

package com.example.tableplay;public class MsgDefine {    public static final int MSG_TYPE_REFRESH = 1;    public static final int MSG_TYPE_VIBROTOR = 2;}
The above is the implementation of all the code of the mini-game. It is rough and I hope there will be a chance to optimize it later.



Copyright Disclaimer: This article is an original article by the blogger and cannot be reproduced without the permission of the blogger.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.