Unity基于NGUI的简单并可直接使用的虚拟摇杆实现(一)
可能大家都听说过大名鼎鼎的easytouch,然而easytouch是基于UGUI的,两种不同的UI混用,可能会造成项目管理的混乱,并且可能会出现各种幺蛾子,比如事件传递互相扰乱的问题。
于是就想找一种基于NGUI的摇杆,搜索网上的文章,都有很多问题,总结来说三个问题很突出。
一:代码本事存在缺陷或者BUG,或者想得太简单,比如没有考虑手指相对按钮的偏移,造成实际并不实用,只能用来学习。
二:号称是NGUI的摇杆,但是有些实现却用了UGUI的东西。
三:未考虑通用性,参数都是固定值,什么43啊73啊,都不知道这些值怎么来的。
于是自己写吧,NGUI怎么用就不教了。
①首先,创建两个Sprite(我这里偷懒用了2DSprite,因为不用打包图片)和一个Texture。
NGuiJoystick是摇杆的底盘,Thumb是摇杆的按钮,NGuiJoystickArea用于Dynamic模式的显示区域。
Dynamic模式:类似于EasyTouch插件的Dynamic模式,平时不显示摇杆,手指按下在手指处显示摇杆,放开手指摇杆消失。
注意:三个UI对象名字随意,但是层级关系不能错。
②修改NGuiJoystick和Thumb的纹理图片并调整到你想要的合适大小(这里最好长宽相等,因为不等我没有试过行不行),给NGuiJoystick和Thumb都Attack上Collider。设置NGuiJoystick的depth为100,Thumb的depth为101(尽可能处于最上层,当然也可根据需求来改)。
③修改NGuiJoystickArea的大小(根据Dynamic模式下你想显示的区域,我这里铺满了全屏),Attack上Collider,修改NGuiJoystickArea的纹理(我这里用了一张白色方向纹理),设置NGuiJoystickArea的color hint的值为(255,,255,255,50),修改depth为1(如果UIRoot和UICamera都是默认值0的话)。
④接下来就是代码部分。
- using System.Collections;
- using System.Collections.Generic;
- using UnityEngine;
- public class JoyStickControl : MonoBehaviour
- {
- public enum ShowType{Static,Dynamic}; //显示模式
- public ShowType showType= ShowType.Static;
- public float radiusOffset = 0.0F; //半径偏移值、用于图片问题造成的偏差进行微调
- public GameObject area = null; //Dynamic模式下的显示区域
- private float radius; //底盘半径
- private float ratio=1.0F; //缩放值
- private bool isPress = false; //是否是按下状态
- private bool isFirstPress = false; //是否第一次按下
- private Vector2 offset; //手指相对于按钮的偏移值
- private void Awake()
- {
- //获取底盘半径
- UI2DSprite parentSpirite = transform.parent.GetComponent<UI2DSprite>();
- float parentWidth = parentSpirite.width;
- radius = parentWidth / 2.0F+ radiusOffset;
- //获取缩放值
- UIRoot root = GameObject.FindObjectOfType<UIRoot>();
- if (root != null)
- {
- // 实际尺寸和设计尺寸比例
- ratio = (float)root.activeHeight / Screen.height;
- }
- //如果是Dynamic模式、一开始隐藏摇杆、并将Area设置到近乎透明
- if (showType == ShowType.Dynamic)
- {
- transform.parent.gameObject.SetActive(false);
- if (area != null)
- {
- UITexture areaTexture = area.GetComponent<UITexture>();
- areaTexture.color = new Color(1.0F, 1.0F, 1.0F, 1.0F/255.0F);
- }
- }
- else
- {
- if (area != null)
- {
- area.SetActive(false);
- }
- }
- }
- // Update is called once per frame
- private void Update()
- {
- // 触摸按下
- if (isPress)
- {
- //最后一次触摸位置、基于屏幕坐标
- Vector2 touchpos = UICamera.lastEventPosition;
- //获取摇杆按钮的屏幕坐标
- Vector2 childCenterPos = UICamera.currentCamera.WorldToScreenPoint(transform.position);
- //第一次触摸的时候获取手指相对于按钮的偏移值
- if (!isFirstPress)
- {
- offset = touchpos - childCenterPos;
- isFirstPress = true;
- }
- //获取摇杆底盘的屏幕坐标
- Vector2 centerPos = UICamera.currentCamera.WorldToScreenPoint(transform.parent.position);
- //获取touchpos - offset和centerPos之间的距离值
- //凡是用到touchpos - offset的地方绝对不能用childCenterPos替代、可以考虑下为什么
- float distance = Vector2.Distance(touchpos - offset, centerPos);
- //如果距离小于半径,则将按钮位置移动到touchpos - offset位置
- //distance算到的相对距离,需要乘以缩放值
- if (distance * ratio < radius)// 距离在父精灵背景中圆内,radius为其半径
- {
- Vector3 worldTouchPos = UICamera.currentCamera.ScreenToWorldPoint(touchpos - offset);
- transform.position = worldTouchPos;
- }
- //距离超过半径、则把按钮的位置设置在底盘的圆上
- else
- {
- transform.localPosition = (touchpos - offset - centerPos).normalized * radius;
- childCenterPos = UICamera.currentCamera.WorldToScreenPoint(transform.position);
- }
- }
- // 触摸抬起、那么把按钮位置恢复到原点、 将isFirstPress置否,如果是Dynamic模式、还要隐藏摇杆
- else
- {
- if (showType == ShowType.Dynamic)
- {
- transform.parent.gameObject.SetActive(false);
- }
- transform.localPosition = Vector2.zero;
- isFirstPress = false;
- }
- }
- // 触摸按下、isPress为true、抬起为false
- public void OnPress(bool isPress)
- {
- this.isPress = isPress;
- }
- //用于Dynamic模式press事件的响应
- public void startTouch()
- {
- if (showType == ShowType.Dynamic)
- {
- transform.parent.gameObject.SetActive(true);
- Vector2 startTouchPos = UICamera.lastEventPosition;
- Vector2 startTouchWorldPos = UICamera.currentCamera.ScreenToWorldPoint(startTouchPos);
- transform.parent.position = startTouchWorldPos;
- this.isPress = true;
- }
- }
- //用于Dynamic模式release事件的响应
- public void endTouch()
- {
- if (showType == ShowType.Dynamic)
- {
- transform.parent.gameObject.SetActive(false);
- }
- transform.localPosition = Vector2.zero;
- isFirstPress = false;
- }
- }
⑤把脚本拖到thumb对象上,并且把NGuiJoystickArea拖到脚本的public成员上。
⑥增加一个事件触发器,NGuiJoystickArea->Add Component->NGUI->Interaction->Event Trigger。
⑦将Thumb拖到触发器press事件上,并设置响应函数为startTouch();将Thumb拖到触发器release事件上,并设置响应函数为endTouch()。
【预览】
过几天再上传和人物的关联文章,实现EasyTouch的allow turn and move,已经DeadValue等一些配置参数。
【本文为原创文章,CSDN博客发布作者和博客园作者为同一作者,特此说明】
Unity基于NGUI的简单并可直接使用的虚拟摇杆实现(一)的更多相关文章
- Unity编辑器:基于NGUI的引用检测工具
这里共享一个基于NGUI的引用检测工具.工具包括几个部分:Atlas/Sprite的引用查找:字库引用查找:UITexture引用查找:Component查找: 代码就不多介绍了,文章底部提供源码下载 ...
- 【转】发布一个基于NGUI编写的UI框架
发布一个基于NGUI编写的UI框架 1.加载,显示,隐藏,关闭页面,根据标示获得相应界面实例 2.提供界面显示隐藏动画接口 3.单独界面层级,Collider,背景管理 4.根据存储的导航信息完成界面 ...
- Unity的NGUI插件篇——入场效果
Unity的NGUI插件篇--入场效果 入场效果 入场效果须要借助于NGUI提供的TweenPosition类来完毕.为了说明此类的用法.本节将使会解说两个演示样例.本文选自 大学霸 <NGU ...
- Unity插件-NGUI使用教程
Unity插件-NGUI使用教程 本文提供全流程,中文翻译.Chinar坚持将简单的生活方式,带给世人!(拥有更好的阅读体验 -- 高分辨率用户请根据需求调整网页缩放比例) 1 NGUI 一款强大的次 ...
- 基于modelsim-SE的简单仿真流程—下
基于modelsim-SE的简单仿真流程—下 编译 在 WorkSpace 窗口的 counter_tst.v上点击右键,如果选择Compile selected 则编译选中的文件,Compile A ...
- 基于modelsim-SE的简单仿真流程—上
基于modelsim-SE的简单仿真流程 编写RTL功能代码 要进行功能仿真,首先得用需要仿真的模块,也就是RTL功能代码,简称待测试的模块,该模块也就是在设计下载到FPGA的电路.一个电路模块想要有 ...
- [置顶] 使用红孩儿工具箱完成基于Cocos2d-x的简单游戏动画界面
[Cocos2d-x相关教程来源于红孩儿的游戏编程之路CSDN博客地址:http://blog.csdn.net/honghaier 红孩儿Cocos2d-X学习园地QQ3群:205100149,47 ...
- [Unity]Unity开发NGUI代码实现ScrollView(放大视图)
Unity开发NGUI代码实现ScrollView(放大视图) 下载NGUI包 导入NGUI3.9.1版本package 创建MainCameraScript.cs脚本 MainCameraScrip ...
- [Unity]Unity开发NGUI代码实现ScrollView(滚动视图)
Unity开发NGUI代码实现ScrollView(滚动视图) 下载NGUI包 导入NGUI3.9.1版本package 链接: http://pan.baidu.com/s/1mgksPBU 密码: ...
随机推荐
- laravel-admin(自定义表单视图)
前言: 在上一遍文章(https://www.cnblogs.com/shiwenhu/p/10271013.html)中写到可以使用自定义form组建来创建表单,几乎能满足我们大部分要求,而且不用我 ...
- node中的session的使用
Session不是一个天生就有的技术,它的使用需要依赖cookie. session依赖cookie,当一个浏览器禁用cookie的时候,登陆效果消失: 或者用户清除了cookie,登陆也消失,ses ...
- 21 | 移动测试神器:带你玩转Appium
- SQL 对float类型列进行排序引发的异常
车祸现场 要求:根据学分和完成时间获取前200名学员,当学分相同时,完成时间较早的排在前面 可以明显看到,完成时间为4.1号的记录排在了3.27号前面. 事故原因 float 表示近似数值,存在精度损 ...
- java虚拟机-程序计数器PC Register
什么是程序计数器? 程序计数器是一块 较小 的内存空间,它可以看做是当前线程所执行的字节码的 行号指示器 :在虚拟机的概念模型里(仅仅是概念模型,各种虚拟机可能会通过一些更高效的方式去实现),字节码解 ...
- HDU 4462:Scaring the Birds(暴力枚举+状态压缩)
http://acm.hdu.edu.cn/showproblem.php?pid=4462 题意:有一个n*n的地图,有k个空地可以放稻草人,给出每个空地可以放的稻草人属性,属性中有个R代表这个位置 ...
- redux和react-redux做简单组件控制
这次我们用两种方式实现以下要求 1.三个组件 2.第一个组件有两个按钮 分别控制第二和第三个组件年龄和姓名的改变 3第二个组件展示姓名,第三个组件展示年龄 用到哪些插件 store redux 一 ...
- .NET Core学习笔记(1)——在Linux下运行Console APP
都说.NET Core可以跨平台,说实话Linux咱也不太懂,咱也不敢问.怎样把一个简单的Console App在Linux下跑起来,真是费了我一番功夫.特做此篇以供指北. .NET Core的大饼我 ...
- django基础知识之Ajax:
使用Ajax 使用视图通过上下文向模板中传递数据,需要先加载完成模板的静态页面,再执行模型代码,生成最张的html,返回给浏览器,这个过程将页面与数据集成到了一起,扩展性差 改进方案:通过ajax的方 ...
- 《Python 3网络爬虫开发实战中文》超清PDF+源代码+书籍软件包
<Python 3网络爬虫开发实战中文>PDF+源代码+书籍软件包 下载: 链接:https://pan.baidu.com/s/18yqCr7i9x_vTazuMPzL23Q 提取码:i ...