可能大家都听说过大名鼎鼎的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的简单并可直接使用的虚拟摇杆实现(一)的更多相关文章

  1. Unity编辑器:基于NGUI的引用检测工具

    这里共享一个基于NGUI的引用检测工具.工具包括几个部分:Atlas/Sprite的引用查找:字库引用查找:UITexture引用查找:Component查找: 代码就不多介绍了,文章底部提供源码下载 ...

  2. 【转】发布一个基于NGUI编写的UI框架

    发布一个基于NGUI编写的UI框架 1.加载,显示,隐藏,关闭页面,根据标示获得相应界面实例 2.提供界面显示隐藏动画接口 3.单独界面层级,Collider,背景管理 4.根据存储的导航信息完成界面 ...

  3. Unity的NGUI插件篇——入场效果

    Unity的NGUI插件篇--入场效果 入场效果 入场效果须要借助于NGUI提供的TweenPosition类来完毕.为了说明此类的用法.本节将使会解说两个演示样例.本文选自  大学霸 <NGU ...

  4. Unity插件-NGUI使用教程

    Unity插件-NGUI使用教程 本文提供全流程,中文翻译.Chinar坚持将简单的生活方式,带给世人!(拥有更好的阅读体验 -- 高分辨率用户请根据需求调整网页缩放比例) 1 NGUI 一款强大的次 ...

  5. 基于modelsim-SE的简单仿真流程—下

    基于modelsim-SE的简单仿真流程—下 编译 在 WorkSpace 窗口的 counter_tst.v上点击右键,如果选择Compile selected 则编译选中的文件,Compile A ...

  6. 基于modelsim-SE的简单仿真流程—上

    基于modelsim-SE的简单仿真流程 编写RTL功能代码 要进行功能仿真,首先得用需要仿真的模块,也就是RTL功能代码,简称待测试的模块,该模块也就是在设计下载到FPGA的电路.一个电路模块想要有 ...

  7. [置顶] 使用红孩儿工具箱完成基于Cocos2d-x的简单游戏动画界面

    [Cocos2d-x相关教程来源于红孩儿的游戏编程之路CSDN博客地址:http://blog.csdn.net/honghaier 红孩儿Cocos2d-X学习园地QQ3群:205100149,47 ...

  8. [Unity]Unity开发NGUI代码实现ScrollView(放大视图)

    Unity开发NGUI代码实现ScrollView(放大视图) 下载NGUI包 导入NGUI3.9.1版本package 创建MainCameraScript.cs脚本 MainCameraScrip ...

  9. [Unity]Unity开发NGUI代码实现ScrollView(滚动视图)

    Unity开发NGUI代码实现ScrollView(滚动视图) 下载NGUI包 导入NGUI3.9.1版本package 链接: http://pan.baidu.com/s/1mgksPBU 密码: ...

随机推荐

  1. 19 | 真实的战场:如何在大型项目中设计GUI自动化测试策略

  2. 可用的NTP服务器地址

    国内可用的Internet时间同步服务器地址(NTP时间服务器)好在阿里云提供了7个NTP时间服务器也就是Internet时间同步服务器地址 ntp1.aliyun.comntp2.aliyun.co ...

  3. 跟我学SpringCloud | 第八篇:Spring Cloud Bus 消息总线

    SpringCloud系列教程 | 第八篇:Spring Cloud Bus 消息总线 Springboot: 2.1.6.RELEASE SpringCloud: Greenwich.SR1 如无特 ...

  4. 新手如何学python?

    在学习Python前,你应该规划好自己的学习方向,毕竟Python的方向比较多,比如: web开发 爬虫 自动化开发(运维,测试).脚本开发 大数据(数据挖掘,数据分析) 人工智能.机器学习 选择好自 ...

  5. Python基础-使用range创建数字列表以及简单的统计计算和列表解析

    1.使用函数 range() numbers = list(range[1,6]) print (numbers) 结果: [1,2,3,4,5] 使用range函数,还可以指定步长,例如,打印1~1 ...

  6. Codeforces 755A:PolandBall and Hypothesis(暴力)

    http://codeforces.com/problemset/problem/755/A 题意:给出一个n,让你找一个m使得n*m+1不是素数. 思路:暴力枚举m判断即可. #include &l ...

  7. django实战仿慕课网在线视频网站(完成了85%以上的功能已上传github:https://github.com/huwei86/mxonline):

    1. 前台功能模块 基本模块:登录 注册 找回密码 / 全局搜索 / 个人中心, 课程功能:课程管理 / 讲师管理 / 授课机构管理  热门推荐 相关课程推荐 用户操作管理:用户收藏 / 课程评论   ...

  8. Weblogic 'wls-wsat' XMLDecoder 反序列化_CVE-2017-10271漏洞复现

    Weblogic 'wls-wsat' XMLDecoder 反序列化_CVE-2017-10271漏洞复现 一.漏洞概述  WebLogic的 WLS Security组件对外提供webservic ...

  9. ~~函数基础(二):返回值&作用域~~

    进击のpython 函数的返回值和作用域 上文我们讲到了函数的基础--参数的相关问题 举的例子也都是带有print的函数定义 但是有个问题就出现了:我不想打印这个函数处理后的参数 我想拿到这个参数然后 ...

  10. 高性能javascript-总结(一)

    性能优化 第一章:加载和执行 总结: 将所有<script>标签放到页面底部.这能确保在脚本执行前页面已经渲染了. 合并脚本.<script>标签越少,加载越快,响应速度也更迅 ...