Android游戏开发二十四】360°平滑游戏摇杆(触屏方向导航)

本站文章均为 李华明Himi 原创,转载务必在明显处注明:(作者新浪微博: @李华明Himi )
转载自【黑米GameDev街区】原文链接: http://www.himigame.com/android-game/384.html

          ☞ 点击订阅 ☜
本博客最新动态!及时将最新博文通知您!

                

分享
 

此章节为正在创作的游戏开发书籍书稿中的一部分,由于写书的缘故很久没有更新了,挺对不起大家的;那么今天放出书稿中的一部分,让大家先睹为快吧;

在Android系统的手机,有的根本没有实体的上下左右导航按键,所以很多游戏都会有利用Android手机都具有触屏的特性,制作360度摇杆来取代游戏方向键,这样不仅能使界面UI变得很美观,而且更加的方便操作;

下面先来看效果吧:

下面开始实现:

首先,肯定是绘制两个圆形,无可置疑;圆心点重合,为了区分 ,所以设置了不同颜色;

灰色:固定不动的摇杆背景(也意味着摇杆的活动范围);

红色:摇杆;

然后考虑:红色摇杆肯定跟随手指触屏的位置而移动,那么这个很easy啦,只要在触屏事件中处理,将获取的触屏XY坐标赋值与摇杆XY坐标即可;这个没问题;但是紧接着在思考一个问题:

一般情况下,我们不可能希望摇杆一直跟随手指位置,所以需要一个摇杆的活动区域,也就如同上图中的灰色区域,在灰色区域内摇杆可以随着用户的触屏位置移动,但是一旦用户触屏位置在活动区域之外,摇杆就不应该跑出灰色区域;所以具体实现步骤如下:

1) 得到通过摇杆的坐标与触屏点的坐标得到所形成的角度Angle

2) 根据Angle,以及已知所在圆的半径,算出摇杆所在灰色圆形上做圆周运动的当前X,Y坐标;

首先第一步: 算出摇杆坐标与触屏坐标形成的角度

我们肯定已知摇杆当前坐标,并且当用户触屏时的坐标也可以在触屏按键中得到,那么获取的方法就可以写成一个方法,方法如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/***
* 得到两点之间的弧度
*/
public double getRad(float px1, float py1, float px2, float py2) {
    //得到两点X的距离
    float x = px2 - px1;
    //得到两点Y的距离
    float y = py1 - py2;
    //算出斜边长
    float xie = (float) Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2));
    //得到这个角度的余弦值(通过三角函数中的定理 :邻边/斜边=角度余弦值)
    float cosAngle = x / xie;
    //通过反余弦定理获取到其角度的弧度
    float rad = (float) Math.acos(cosAngle);
    //注意:当触屏的位置Y坐标<摇杆的Y坐标我们要取反值-0~-180
    if (py2 < py1) {
        rad = -rad;
    }
    return rad;
}

在Java中 Math类中的反余弦函数返回的不是角度是弧度,这一点要格外注意;

另外一点就是,因为三角函数角度范围是0~180度,所以反之应该是-0~-180度;

通过此函数获取到摇杆与用户触屏位置所形成的角度之后,我们就可以通过圆周公式来得到其摇杆的XY坐标了;方法如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/**
*
* @param R
*            圆周运动的旋转点
* @param centerX
*            旋转点X
* @param centerY
*            旋转点Y
* @param rad
*            旋转的弧度
*/
public void getXY(float centerX, float centerY, float R, double rad) {
    //获取圆周运动的X坐标
    SmallRockerCircleX = (float) (R * Math.cos(rad)) + centerX;
    //获取圆周运动的Y坐标
    SmallRockerCircleY = (float) (R * Math.sin(rad)) + centerY;
}

圆周运动公式:通过三角函数定理得出:

X坐标:所在圆的半径*角度的余弦值

Y坐标:所在圆形半径*角度的正弦值

圆周的大小,由所在圆的半径R的大小来决定;

通过以上的公式我们就可以让摇杆在灰色圆形上做圆周运动,当然除此之外我们还要注意三点:

1:做圆周运动的大小,应该跟灰色区域的半径相同;

2:触屏事件中应该首先判定用户触屏的位置是否在灰色区域中,如果不在,我们就应该获取摇杆与触屏点的角度然后获取摇杆应该在圆周运动上的XY坐标;如果在,就没有处理了,只要将摇杆位置随着用户点击位置就好了;

3:在触屏事件中,当用户手指离开屏幕后,应该让摇杆的位置恢复到初始的位置状态;

下面是整个项目的MySurfaceView中全部代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
package com.rp;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.Log;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.SurfaceHolder.Callback;
public class MySurfaceView extends SurfaceView implements Callback, Runnable {
    private Thread th;
    private SurfaceHolder sfh;
    private Canvas canvas;
    private Paint paint;
    private boolean flag;
    //固定摇杆背景圆形的X,Y坐标以及半径
    private int RockerCircleX = 100;
    private int RockerCircleY = 100;
    private int RockerCircleR = 50;
    //摇杆的X,Y坐标以及摇杆的半径
    private float SmallRockerCircleX = 100;
    private float SmallRockerCircleY = 100;
    private float SmallRockerCircleR = 20;
    public MySurfaceView(Context context) {
        super(context);
        Log.v("Himi", "MySurfaceView");
        this.setKeepScreenOn(true);
        sfh = this.getHolder();
        sfh.addCallback(this);
        paint = new Paint();
        paint.setAntiAlias(true);
        setFocusable(true);
        setFocusableInTouchMode(true);
    }
    public void surfaceCreated(SurfaceHolder holder) {
        th = new Thread(this);
        flag = true;
        th.start();
    }
    /***
     * 得到两点之间的弧度
     */
    public double getRad(float px1, float py1, float px2, float py2) {
        //得到两点X的距离
        float x = px2 - px1;
        //得到两点Y的距离
        float y = py1 - py2;
        //算出斜边长
        float xie = (float) Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2));
        //得到这个角度的余弦值(通过三角函数中的定理 :邻边/斜边=角度余弦值)
        float cosAngle = x / xie;
        //通过反余弦定理获取到其角度的弧度
        float rad = (float) Math.acos(cosAngle);
        //注意:当触屏的位置Y坐标<摇杆的Y坐标我们要取反值-0~-180
        if (py2 < py1) {
            rad = -rad;
        }
        return rad;
    }
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if (event.getAction() == MotionEvent.ACTION_DOWN ||
                    event.getAction() == MotionEvent.ACTION_MOVE) {
            // 当触屏区域不在活动范围内
            if (Math.sqrt(Math.pow((RockerCircleX - (int) event.getX()), 2)
                    + Math.pow((RockerCircleY - (int) event.getY()), 2)) >= RockerCircleR) {
                //得到摇杆与触屏点所形成的角度
                double tempRad = getRad(RockerCircleX, RockerCircleY, event.getX(), event.getY());
                //保证内部小圆运动的长度限制
                getXY(RockerCircleX, RockerCircleY, RockerCircleR, tempRad);
            } else {//如果小球中心点小于活动区域则随着用户触屏点移动即可
                SmallRockerCircleX = (int) event.getX();
                SmallRockerCircleY = (int) event.getY();
            }
        } else if (event.getAction() == MotionEvent.ACTION_UP) {
            //当释放按键时摇杆要恢复摇杆的位置为初始位置
            SmallRockerCircleX = 100;
            SmallRockerCircleY = 100;
        }
        return true;
    }
    /**
     *
     * @param R
     *            圆周运动的旋转点
     * @param centerX
     *            旋转点X
     * @param centerY
     *            旋转点Y
     * @param rad
     *            旋转的弧度
     */
    public void getXY(float centerX, float centerY, float R, double rad) {
        //获取圆周运动的X坐标
        SmallRockerCircleX = (float) (R * Math.cos(rad)) + centerX;
        //获取圆周运动的Y坐标
        SmallRockerCircleY = (float) (R * Math.sin(rad)) + centerY;
    }
    public void draw() {
        try {
            canvas = sfh.lockCanvas();
            canvas.drawColor(Color.WHITE);
            //设置透明度
            paint.setColor(0x70000000);
            //绘制摇杆背景
            canvas.drawCircle(RockerCircleX, RockerCircleY, RockerCircleR, paint);
            paint.setColor(0x70ff0000);
            //绘制摇杆
            canvas.drawCircle(SmallRockerCircleX, SmallRockerCircleY,
                    SmallRockerCircleR, paint);
        } catch (Exception e) {
            // TODO: handle exception
        } finally {
            try {
                if (canvas != null)
                    sfh.unlockCanvasAndPost(canvas);
            } catch (Exception e2) {
            }
        }
    }
    public void run() {
        // TODO Auto-generated method stub
        while (flag) {
            draw();
            try {
                Thread.sleep(50);
            } catch (Exception ex) {
            }
        }
    }
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
        Log.v("Himi", "surfaceChanged");
    }
    public void surfaceDestroyed(SurfaceHolder holder) {
        flag = false;
        Log.v("Himi", "surfaceDestroyed");
    }
}

360°平滑游戏摇杆(触屏方向导航)相关推荐

  1. unity中2D飞机游戏手指触屏操作的问题

    unity中2D飞机游戏手指触屏操作的问题 菜鸡记录一下在项目中遇到的坑 下面就是我用的代码 if (UnityEngine.Input.touchCount > 0) //每一帧触摸到的屏幕的 ...

  2. Java游戏触屏处理,非触屏java游戏转换为触屏游戏工具使用方法

    用下面软件可以把非触屏java游戏改为触屏游戏,不会遮挡屏幕,提供了9个可自设触摸键,真是玩rpg类游戏的大福音啊!方法如下: 一.下载HandyPartner.JavaMagic_60b.和halo ...

  3. linux笔记本触屏方向反了,[已解决]如何设置触摸板上下滚屏反转(像mac一样,和windows是反的)...

    先用以下命令看设备id: xinput 我的 Synaptics 触摸板的 id 是 13,下面就以 13 为例. 用 xinput list-props 13 可以列出设备属性,有一项应该是这样: ...

  4. 常用的jquery触屏手机页面特效代码下载

    js手机幻灯片代码制作手指滑动手机端图片轮播代码 jQuery移动端页面侧边导航菜单滑出效果代码 jquery.touchswipe.js手机端网页制作触屏滑动导航显示代码 jquery响应式幻灯片插 ...

  5. cocos2d-x 横板游戏触屏人物和背景移动 方法1

    大多横板游戏主角的移动都是有背景一起在移动的,不单单是主角在动.当主角的位置离地图的左端距离小于屏幕宽度的一半或者主角离地图最右端的距离小于屏幕宽度的一半时,触屏之后就人物在移动,背景没有动,当主角位 ...

  6. Unity3D 游戏引擎之IOS自定义游戏摇杆与飞机平滑的移动(十一)

    Unity3D 游戏引擎之IOS自定义游戏摇杆与飞机平滑的移动 雨松MOMO原创文章如转载,请注明:转载至我的独立域名博客雨松MOMO程序研究院,原文地址:http://www.xuanyusong. ...

  7. 【iOS-Cocos2d游戏开发之五】【1】多触点与触屏事件详解(单一监听、事件分发)...

    本站文章均为 李华明Himi 原创,转载务必在明显处注明: 转载自[黑米GameDev街区] 原文链接: http://www.himigame.com/iphone-cocos2d/450.html ...

  8. html5 接东西游戏,html5手机触屏接红包小游戏代码

    特效描述:html5手机触屏 接红包小游戏.canvas 红包下落点击接住红包,结束计算金额及红包个数.请用手机扫码打开正常演示. 代码结构 1. 引入CSS 2. 引入JS 3. HTML代码 fu ...

  9. cocos2d-x游戏实例(11)-触屏主角移动轨迹

    小满(bill man)个人原创,欢迎转载,转载请注明地址,小满(bill man)的专栏地址http://blog.csdn.net/bill_man 最近在玩间谍鼠这个游戏,其中有一个触屏操作主角 ...

最新文章

  1. qiime2安装和使用案例
  2. 什么是智能仓储?一文带你彻底搞懂!
  3. [原创]使用ajaxFileUpload.js上传文件时附带额外参数。
  4. python多元线性回归模型_python – 使用Tensorflow的多元线性回归模型
  5. C++知识点1——基础
  6. C#中怎样将数组的顺序打乱随机排序
  7. ICCV 2021 | G-SFDA:无需源数据的领域自适应方法
  8. Dalvik/ART(ANDROID)中的多线程机制(3)
  9. SAP UI5 subscribe event实现原理
  10. ANSYS-CFX,计算时报错,内存参数报错,return code 1【终极解决方案】
  11. 数组随机排序(随手记)
  12. Type interface com.zhaoka.mapper.DatKcardKmMapper is not known to the MapperRegistry
  13. PIM DM技术原理与实验
  14. mysql多实例my.cnf_mysql多实例,my.cnf 4G conf配置安装配置
  15. PowerShell、CMD 和 Windows Terminal 的美化配置方法
  16. 第三篇第九章火灾自动报警系统
  17. 不良事件总结怎么写_年度不良事件总结
  18. 学术规范作业——心得体会
  19. android用代码返回桌面
  20. C语言一般考点笔试,c语言常见笔试题及答案

热门文章

  1. mt6592 [Speech]修改acoustic loopback时延时
  2. Alibaba后台4年,跳槽字节,艰难4面技术,成功砍下开发岗offer
  3. Mybatis报错There is no getter for property named 'id' in 'class java.lang.String'
  4. linux防火墙iptables常用应用功能实现
  5. “聚力远谋,创赢未来”坤前全国巡展广州站圆满落幕
  6. 数据科学课程笔记1 --- 导论
  7. flutter 发送验证码
  8. 无线互联 嵌入式系统设计的新挑战
  9. 移动盒子——双向链表
  10. PHP base64 编码转化图片并进行指定路径的保存和上传处理