作为一个没有学习Android的菜鸟,最近一直在工作之外努力地学习的Android的使用。这周看了下Android的绘图,主要是Canvas,Paint等,感觉需要实践下,下午正好有空,就想整一个乒乓球的游戏,算是巩固学的知识。

首先,需要了解下Android的绘图需要掌握的常用类,包括Canvas,就像一个画板一样,所有的东西都是在其上画的;Paint就是画笔,用其可以画各种基本图形和文字。       Canvas和Paint常用的方法就不列举了,这样的东西网上到处是。有了这两个东西,想实现游戏,还差个手势感应,对这个游戏来说,只需要识别出左移和右移即可。

为此,我们需要使用Android的OnGestureListener接口和GestureDetector类。

重要的方法如下所示:

    GestureDetector detector;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_start);detector = new GestureDetector(this, this);}@Overridepublic boolean onTouchEvent(MotionEvent event) {// TODO Auto-generated method stubreturn detector.onTouchEvent(event);}@Overridepublic boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {// 最小移动标准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;}

我们需要在onTouchEvent中使用调用GestureDetector的onTouchEvent()方法,只有这样手势感应的接口才可以被回调。其中,onFling()方法中,我们实现了左移和右移的判断。

游戏的截图如下所示:

实现该游戏,主要需要考虑的地方有以下几个地方:

1.游戏的状态如何描述,具体来说,就是小球和球拍的状态

2.视图如何动态刷新

对问题1来说,球拍的状态比较简单,只有左移和右移两种,设置球拍的x,y坐标,利用步长就可很好改变,小球的话,稍微麻烦一些,我们需要用其x,y坐标,x移动速度和y移动速度来控制其状态,碰到左右强,x速度反转,碰到球拍或者上边y速度反转,碰到下边(未碰到球拍)则比赛结束。

对问题2来说,我们需要启动定时刷新任务,定时执行判断当前状态,然后根据数据来刷新视图。

下面就主要介绍下自己的小游戏实现了,代母包含以下几个类,TablePlayActivity,TableView,MsgDefine,TablePlayModel,TablePlayController。

TablePlayActivity如下:

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 OnGestureListener{private GestureDetector dector;private TableView myView;private Vibrator vibrator;@Overrideprotected 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.getDefaultDisplay().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() {@Overridepublic 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(1000);Toast.makeText(TablePlayActivity.this, "Nice", Toast.LENGTH_SHORT).show();break;}default :break;}}};}@Overridepublic 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;}@Overridepublic 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);}@Overridepublic boolean onTouchEvent(MotionEvent event) {return dector.onTouchEvent(event);}@Overridepublic boolean onDown(MotionEvent e) {// TODO Auto-generated method stubreturn false;}@Overridepublic void onShowPress(MotionEvent e) {// TODO Auto-generated method stub}@Overridepublic boolean onSingleTapUp(MotionEvent e) {// TODO Auto-generated method stubreturn false;}@Overridepublic boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {// TODO Auto-generated method stubreturn false;}@Overridepublic void onLongPress(MotionEvent e) {// TODO Auto-generated method stub}@Overridepublic boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {// 最小移动标准float minMove = 30;if ((e1.getX() - e2.getX()) > minMove && Math.abs(velocityX) > Math.abs(velocityY)) {// 左移TablePlayController.getInstance().racketMoveLeft();} else if ((e2.getX() - e1.getX()) > minMove && Math.abs(velocityX) > Math.abs(velocityY)) {// 右移TablePlayController.getInstance().racketMoveRight();}// 重绘ViewmyView.invalidate();return false;}
}

在TablePlayActivity类中,我们主要实现了手势感应的判断和Handler消息的处理,另外初始化中获取了屏幕的宽和高。
TableView是我们主要的画图类,我们在其的onDraw方法中,实现了小球和球拍的重绘,代码如下:

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;// 创建画笔paint = new Paint();paint.setAntiAlias(true);paint.setStyle(Style.FILL);}@Overrideprotected 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.setColor(Color.GREEN);canvas.drawRect(data.mRacketX, data.mRacketY, data.mRacketX + data.RACKET_WIDTH,data.mRacketY + data.RACKET_HEIGHT, paint);// 画球paint.setColor(Color.GRAY);canvas.drawCircle(data.mBallX, data.mBallY, data.mBallRadius, paint);}}
}

接下来是数据类TablePlayModel,该类主要缓存我们需要使用的数据,包括我们所有需要使用的游戏状态和常量,代码如下:

package com.example.tableplay;import java.util.Random;import android.util.Log;public class TablePlayModel {private static TablePlayModel mInstance = null;// 屏幕的宽和高public int mScreenX;public int mScreenY;// 球拍的宽度和高度public final int RACKET_WIDTH = 180;public final int RACKET_HEIGHT = 25;// 球拍移动的步长public int mRacketStep = 150;// 球拍的水平和垂直位置public int mRacketX = 100;public int mRacketY;private Random rand = new Random();// 小球的半径public int mBallRadius = 35;// 小球的x,y坐标public int mBallX = rand.nextInt(200) + 20;public int mBallY = rand.nextInt(500) + 20;// 小球x,y移动速度public int mBallYSpeed = 28;private double mXRate = rand.nextDouble() - 0.5;public int mBallXSpeed = (int) (mBallYSpeed * mXRate * 2);// 刷新间隔 mspublic int mTimeInterval = 100;// 刷新延时 mspublic 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;}
}

接下来是最重要的控制类TablePlayController,我们的核心逻辑都在该类中,具体来说,就是启动定时器执行任务,根据当前的状态执行小球的运动位置,更新小球的坐标,并通知视图刷新界面,代码如下:

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() {@Overridepublic void run() {// 如果碰到左右边界if (data.mBallX <= data.mBallRadius || data.mBallX >= data.mScreenX - data.mBallRadius) {data.mBallXSpeed = -data.mBallXSpeed;}// 如果位置低于球拍的高度但是不在球拍的范围内,则比赛结束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();}// 小球坐标改变data.mBallX += data.mBallXSpeed;data.mBallY += data.mBallYSpeed;// 发送消息Message msg = Message.obtain(handler);msg.what = MsgDefine.MSG_TYPE_REFRESH;msg.sendToTarget();}}, data.mTimeDelay, data.mTimeInterval);}/** 球拍左移*/public void racketMoveLeft() {if (data.mRacketX >= data.mRacketStep) {data.mRacketX += -data.mRacketStep;} else {data.mRacketX = 0;}}/** 球拍右移*/public void racketMoveRight() {if ((data.mRacketX + data.RACKET_WIDTH) < data.mScreenX) {data.mRacketX += data.mRacketStep;} else {data.mRacketX = data.mScreenX - data.RACKET_WIDTH;}}
}

为了实现较好的效果,我们在成功打击球时,会震动一下(需要在AndroidManifest.xml中增加<uses-permission android:name="android.permission.VIBRATE"/>),并弹toast祝贺。

最后剩下的是信息数据类MsgDefine,存放着数据的类型,具体来说,包括刷新消息和震动消息类型,代码如下:

package com.example.tableplay;public class MsgDefine {public static final int MSG_TYPE_REFRESH = 1;public static final int MSG_TYPE_VIBROTOR = 2;
}

以上就是小游戏的全部代码实现,做的比较粗糙,希望后面有机会了可以优化下。

Android使用学习之绘图(Canvas,Paint)与手势感应及其应用(乒乓球小游戏)相关推荐

  1. Python快速编程入门#学习笔记02# |第十章 :Python计算生态与常用库(附.小猴子接香蕉、双人乒乓球小游戏源码)

    全文目录 学习目标 1. Python计算生态概述 1.1 Python计算生态概述 2. Python生态库的构建与发布 2.1 模块的构建与使用 * 2.1.1第三方库/模块导入的格式 2.2 包 ...

  2. android canvas画图gc,自定义控件绘图(Canvas,Paint,Region等)篇一

    参考: 关于绘图相关的 Paint.Canvas多少都接触过一些,但没有系统的学习过,每次都是边查边用,这里都是参考大神的博客而成的学习记录,(采用Kotlin语言,来编写,kotlin确实有些坑,但 ...

  3. Android使用学习之画图(Canvas,Paint)与手势感应及其应用(乒乓球小游戏)

    作为一个没有学习Android的菜鸟,近期一直在工作之外努力地学习的Android的使用. 这周看了下Android的画图.主要是Canvas,Paint等,感觉须要实践下.下午正好有空,就想整一个乒 ...

  4. Canvas 类库ZRender开发的接水果的小游戏

    最近使用了轻量级的 Canvas 类库 ZRender开发了一些自定义图件,所以想试试用zrender开发小游戏怎么样,自己也没什么经验,所以写着玩吧,可能有些逻辑部分写的不是很好..这个小游戏很简单 ...

  5. js canvas仿微信《弹一弹》小游戏

    前言 半年前用js和canvas仿了热血传奇网游(地址),基本功能写完之后,剩下的都是堆数据.堆时间才能完成的任务了,没什么新鲜感,因此进度极慢.这次看到微信<弹一弹>比较火,因为涉及到物 ...

  6. js+canvas仿微信《弹一弹》小游戏

    前言 半年前用js和canvas仿了热血传奇网游(地址),基本功能写完之后,剩下的都是堆数据.堆时间才能完成的任务了,没什么新鲜感,因此进度极慢.这次看到微信<弹一弹>比较火,因为涉及到物 ...

  7. 初学Android,图形图像之使用Canvas,Paint绘图(二十五)

    下面是一个画各种图形的例子,具体的画图方法不用特别解释,看API就可以了 先定义一个继承自View的类DrawView package WangLi.Graphics.MyView;import an ...

  8. 对对碰 代码 android,iOS分段选择器、旅行App、标度尺、对对碰小游戏、自定义相册等源码...

    iOS精选源码 iOS优质博客 前言当前互联网行业的竞争已经是非常激烈了, "功能驱动"的时代已经过去了, 现在更加注重软件的细节, 以及用户的体验问题. 说到用户体验,就不得不提 ...

  9. FishC《零基础学习python》笔记--第004讲:改进我们的小游戏

    测试题: 请问以下代码会打印多少次"我爱鱼C!" while 'C': print('我爱鱼C!') 死循环 请问以下代码会打印多少次"我爱鱼C!" i = 1 ...

最新文章

  1. DOM笔记(五):JavaScript的常见事件和Ajax小结
  2. Windows Azure Platform Introduction (2) 云计算的分类和服务层次
  3. PHP开发之thinkPHP分层设计
  4. category、protocol、delegate总结
  5. 服务器账户登录监控系统,服务器账户登录监控系统
  6. Chrome 控制台不完全指南
  7. c语言 乱码转化为16进制_面向小白的C语言科普教程(一)文件和扩展名、编码和十六进制...
  8. 研讨会 | CCF TF 第 17 期:认知计算产业化落地
  9. 【Flink】Flink 1.12.2 Task的调度 源码
  10. MySQL二十八规范数据库设计
  11. [转载] python json unicode utf-8处理总结
  12. 微信怎么at所有人_变速箱报废、发动机故障、车门下沉,全新马自达3到底怎么了?...
  13. Java开发规范手册(持续更新)
  14. CNC编程工程师如何炼成?要哪些必备技能?
  15. 【适合程序员的代码笔记软件】Quiver 3.2.6 for Mac
  16. ISO20000/ISO27001体系认证最短周期
  17. fast无线路由器设置服务器,迅捷(Fast)FW150R无线路由器设置
  18. 过滤文本中的中英文标点符号、字母、数字、表情
  19. 申请德国农工大学计算机案例,德州农工大学本科案例
  20. springmvc+mybatis环境搭建遇到的错误

热门文章

  1. php模拟报税,当税务遇见RPA:一键报税
  2. 幻想三国志 游戏流程详尽全攻略 1
  3. 分享一个学习ArcGIS二次开发与应用的学习网站
  4. 微信小程序自动化测试的研究过程
  5. python pyinstaller 打包项目
  6. 软件采购必备:软件供应商评估表 之一(共七)
  7. 哲学与科技——唯物史观,人与自然、科学与技术、科技与社会、人与科技的关系的简单描述
  8. word显示多级目录,并且自动对齐
  9. 95页字节跳动内部前端学习笔记在互联网上火了,完整版开放下载
  10. 计算机毕业设计JavaWEB儿童运动馆业务信息系统(源码+系统+mysql数据库+lw文档)