android 贪食蛇教程,Android自定义View系列之《贪吃蛇大作战》方向操作键效果实现...

本文主要是介绍android 贪食蛇教程,Android自定义View系列之《贪吃蛇大作战》方向操作键效果实现...,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

前段时间很火的一款贪吃蛇游戏,可玩性很高,几点规则改造就将传统的贪吃蛇改活了,当时我拿过13000多分,还嘚瑟了很久。今天来个教程10分钟实现它。。。额,不是,实现它的方向操作按钮效果,看下图左下角的那两个同心圆。

c8e4add4780a

贪吃蛇大作战

用户手指触碰屏幕任意位置,内圆就往用户手指那个方向移动至外圆边界内切,实现后效果图如下所示。

c8e4add4780a

效果图

先看两张图,分别是Android坐标系与Android View尺寸函数的含义,其中,Android坐标系往右x轴递增,往下y轴递增,不多说。

c8e4add4780a

Android坐标系

c8e4add4780a

Android-View-Size

下面开始编码

1)创建HandleView类,继承自View

/**

* 贪吃蛇大作战方向控制按钮效果

*/

public class HandleView extends View {

public HandleView(Context context) {

this(context, null);

}

public HandleView(Context context, AttributeSet attrs) {

this(context, attrs, 0);

}

public HandleView(Context context, AttributeSet attrs, int defStyleAttr) {

super(context, attrs, defStyleAttr);

}

@Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

// TODO

super.onMeasure(widthMeasureSpec, heightMeasureSpec);

}

@Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) {

super.onLayout(changed, left, top, right, bottom);

}

@Override protected void onDraw(Canvas canvas) {

super.onDraw(canvas);

// TODO

}

}

上述代码可以作为几乎所有自定义View的初始代码模板。

方向操作按钮等宽等高,我们不想它在xml布局时被设置成宽高不等的长方形,所以需要在onMeasure函数里进行处理。

2)重载onMeasure

@Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

setMeasuredDimension(getDefaultSize2(getSuggestedMinimumWidth(), widthMeasureSpec),

getDefaultSize2(getSuggestedMinimumHeight(), heightMeasureSpec));

int childWidthSize = getMeasuredWidth();

widthMeasureSpec = MeasureSpec.makeMeasureSpec(childWidthSize, MeasureSpec.EXACTLY);

heightMeasureSpec = MeasureSpec.makeMeasureSpec(childWidthSize, MeasureSpec.EXACTLY);

super.onMeasure(widthMeasureSpec, heightMeasureSpec);

}

/**

* Compare to: {@link android.view.View#getDefaultSize(int, int)}

* If mode is AT_MOST, return the child size instead of the parent size

* (unless it is too big).

*/

private static int getDefaultSize2(int size, int measureSpec) {

int result = size;

int specMode = MeasureSpec.getMode(measureSpec);

int specSize = MeasureSpec.getSize(measureSpec);

switch (specMode) {

case MeasureSpec.UNSPECIFIED:

result = size;

break;

case MeasureSpec.AT_MOST:

result = Math.min(size, specSize);

break;

case MeasureSpec.EXACTLY:

result = specSize;

break;

}

return result;

}

3)画外圆

public class HandleView extends View {

private Paint mPaintForCircle;

// ...

@Override protected void onDraw(Canvas canvas) {

super.onDraw(canvas);

// 背景透明

canvas.drawColor(Color.TRANSPARENT);

// 外圆半径

int radiusOuter = getWidth() / 2;

// 内圆半径

int radiusInner = getWidth() / 5;

// 圆心坐标(cx,cy)

float cx = getWidth() / 2;

float cy = getHeight() / 2;

if (null == mPaintForCircle) {

mPaintForCircle = new Paint();

}

mPaintForCircle.setAntiAlias(true);

mPaintForCircle.setStyle(Paint.Style.FILL);

// 画外圆

mPaintForCircle.setColor(Color.argb(0x7f, 0x11, 0x11, 0x11));

canvas.drawCircle(cx, cy, radiusOuter, mPaintForCircle);

// TODO 画内圆

}

}

4)画内圆

内圆是运动的,它的位置与用户的手指触摸坐标有关,按照效果,用户可以触摸的范围是包裹HandleView的ViewGroup(FrameLayout之类的),这里先写个接口用于获取手指触摸坐标。

public class HandleView extends View {

private HandleReaction mHandleReaction;

public void setHandleReaction(HandleReaction handleReaction) {

mHandleReaction = handleReaction;

}

public interface HandleReaction {

/**

* 获取用户触摸坐标

* @return

*/

float[] getTouchPosition();

}

// ...

}

c8e4add4780a

示意图

内圆半径固定,位置由圆心的坐标决定,所以关键是得出内圆的圆心坐标随用户手指的触摸坐标的变化而变化的函数关系,让我们建立方程式:(用工具画太花时间,将就手画,见谅!P.S.好像回到中学有木有)

c8e4add4780a

建立方程组

c8e4add4780a

结果

由公式可得出,分母(开平方根那个数的值)是cx2和cy2都需要的公用的值,命名为ratio,计算代码如下。

float[] touchPosition = mHandleReaction.getTouchPosition();

double ratio = (radiusOuter - radiusInner) /

Math.sqrt(

Math.pow(touchPosition[0] - cx, 2) +

Math.pow(touchPosition[1] - cy, 2));

float cx2 = (float) (ratio * (touchPosition[0] - cx) + cx);

float cy2 = (float) (ratio * (touchPosition[1] - cy) + cy);

mPaintForCircle.setColor(Color.argb(0xff, 0x11, 0x11, 0x11));

canvas.drawCircle(cx2, cy2, radiusInner, mPaintForCircle);

5)获取触摸坐标

建立MainActivity,布局文件就不给出了,文末附带源码地址。

public class MainActivity extends AppCompatActivity

implements HandleView.HandleReaction, View.OnTouchListener {

private float[] mTouchPosition = null;

private HandleView mHandleView;

@Override protected void onCreate(@Nullable Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

FrameLayout frameLayout = (FrameLayout) findViewById(R.id.frameLayout);

frameLayout.setOnTouchListener(this);

mHandleView = (HandleView) findViewById(R.id.handleView);

mHandleView.setHandleReaction(this);

}

@Override public boolean onTouch(View view, MotionEvent motionEvent) {

switch (motionEvent.getAction()) {

case MotionEvent.ACTION_DOWN:

case MotionEvent.ACTION_MOVE: {

mTouchPosition = new float[2];

mTouchPosition[0] = motionEvent.getX();

mTouchPosition[1] = motionEvent.getY();

mHandleView.invalidate();

return true;

}

case MotionEvent.ACTION_UP: {

mTouchPosition = null;

mHandleView.invalidate();

return true;

}

}

return false;

}

@Override public float[] getTouchPosition() {

return mTouchPosition;

}

}

6)坐标修正

表面上,上面内圆圆心计算代码是正确的,但实际上,由于我们的HandleView通过接口从它的父布局那里拿到了触摸坐标与HandleView内部坐标的参考坐标系不是同一个,他们相差一个HandleView相对于它父布局的getLeft与getTop的偏移,参照图Android-View-Size,所以需要对计算代码进行修正,如下:

// 经过修正后的内圆圆心坐标代码

double ratio = (radiusOuter - radiusInner) /

Math.sqrt(

Math.pow(touchPosition[0] - cx - getLeft(), 2) +

Math.pow(touchPosition[1] - cy - getTop(), 2));

float cx2 = (float) (ratio * (touchPosition[0] - cx - getLeft()) + cx);

float cy2 = (float) (ratio * (touchPosition[1] - cy - getTop()) + cy);

最后附上源码地址

GitHub源码

这篇关于android 贪食蛇教程,Android自定义View系列之《贪吃蛇大作战》方向操作键效果实现...的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/154870

相关文章

Python虚拟环境终极(含PyCharm的使用教程)

《Python虚拟环境终极(含PyCharm的使用教程)》:本文主要介绍Python虚拟环境终极(含PyCharm的使用教程),具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,... 目录一、为什么需要虚拟环境?二、虚拟环境创建方式对比三、命令行创建虚拟环境(venv)3.1 基础命令3

Python 中的 with open文件操作的最佳实践

《Python中的withopen文件操作的最佳实践》在Python中,withopen()提供了一个简洁而安全的方式来处理文件操作,它不仅能确保文件在操作完成后自动关闭,还能处理文件操作中的异... 目录什么是 with open()?为什么使用 with open()?使用 with open() 进行

使用Node.js制作图片上传服务的详细教程

《使用Node.js制作图片上传服务的详细教程》在现代Web应用开发中,图片上传是一项常见且重要的功能,借助Node.js强大的生态系统,我们可以轻松搭建高效的图片上传服务,本文将深入探讨如何使用No... 目录准备工作搭建 Express 服务器配置 multer 进行图片上传处理图片上传请求完整代码示例

openCV中KNN算法的实现

《openCV中KNN算法的实现》KNN算法是一种简单且常用的分类算法,本文主要介绍了openCV中KNN算法的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的... 目录KNN算法流程使用OpenCV实现KNNOpenCV 是一个开源的跨平台计算机视觉库,它提供了各

OpenCV图像形态学的实现

《OpenCV图像形态学的实现》本文主要介绍了OpenCV图像形态学的实现,包括腐蚀、膨胀、开运算、闭运算、梯度运算、顶帽运算和黑帽运算,文中通过示例代码介绍的非常详细,需要的朋友们下面随着小编来一起... 目录一、图像形态学简介二、腐蚀(Erosion)1. 原理2. OpenCV 实现三、膨胀China编程(

通过Spring层面进行事务回滚的实现

《通过Spring层面进行事务回滚的实现》本文主要介绍了通过Spring层面进行事务回滚的实现,包括声明式事务和编程式事务,具有一定的参考价值,感兴趣的可以了解一下... 目录声明式事务回滚:1. 基础注解配置2. 指定回滚异常类型3. ​不回滚特殊场景编程式事务回滚:1. ​使用 TransactionT

Android实现打开本地pdf文件的两种方式

《Android实现打开本地pdf文件的两种方式》在现代应用中,PDF格式因其跨平台、稳定性好、展示内容一致等特点,在Android平台上,如何高效地打开本地PDF文件,不仅关系到用户体验,也直接影响... 目录一、项目概述二、相关知识2.1 PDF文件基本概述2.2 android 文件访问与存储权限2.

使用Python实现全能手机虚拟键盘的示例代码

《使用Python实现全能手机虚拟键盘的示例代码》在数字化办公时代,你是否遇到过这样的场景:会议室投影电脑突然键盘失灵、躺在沙发上想远程控制书房电脑、或者需要给长辈远程协助操作?今天我要分享的Pyth... 目录一、项目概述:不止于键盘的远程控制方案1.1 创新价值1.2 技术栈全景二、需求实现步骤一、需求

Spring Shell 命令行实现交互式Shell应用开发

《SpringShell命令行实现交互式Shell应用开发》本文主要介绍了SpringShell命令行实现交互式Shell应用开发,能够帮助开发者快速构建功能丰富的命令行应用程序,具有一定的参考价... 目录引言一、Spring Shell概述二、创建命令类三、命令参数处理四、命令分组与帮助系统五、自定义S

SpringBatch数据写入实现

《SpringBatch数据写入实现》SpringBatch通过ItemWriter接口及其丰富的实现,提供了强大的数据写入能力,本文主要介绍了SpringBatch数据写入实现,具有一定的参考价值,... 目录python引言一、ItemWriter核心概念二、数据库写入实现三、文件写入实现四、多目标写入